fixed val logic, added status

This commit is contained in:
Phani Pavan K
2025-10-20 11:55:32 +05:30
parent d713cc8fa3
commit 06a661b951
8 changed files with 129 additions and 52 deletions

View File

@@ -1,4 +1,4 @@
use crate::app::status::EntryCreation;
use crate::app::status::EntryValError;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
@@ -27,14 +27,16 @@ impl Entry {
toIP: String,
fromPort: String,
toPort: String,
) -> Result<Self, EntryCreation> {
) -> Result<Self, EntryValError> {
let ip = Regex::new("^(?:25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])\\.(?:25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])\\.(?:25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])\\.(?:25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])$").unwrap();
if !fromPort.parse::<i32>().is_ok_and(|a| a > 1 && a < 65535)
|| !toPort.parse::<i32>().is_ok_and(|a| a > 1 && a < 65535)
{
Err(EntryCreation::PortValidationError)
} else if !ip.is_match(fromIP.trim()) || !ip.is_match(toIP.trim()) {
Err(EntryCreation::IPValidationError)
if !ip.is_match(fromIP.trim()) {
Err(EntryValError::FromIPValError)
} else if !fromPort.parse::<i32>().is_ok_and(|a| a > 1 && a < 65535) {
Err(EntryValError::FromPortValError)
} else if !ip.is_match(toIP.trim()) {
Err(EntryValError::ToIPValError)
} else if !toPort.parse::<i32>().is_ok_and(|a| a > 1 && a < 65535) {
Err(EntryValError::ToPortValError)
} else {
Ok(Entry {
fromIP,

View File

@@ -8,7 +8,7 @@ use ratatui::widgets::TableState;
use crate::app::{
entry::Entry,
settings::Settings,
status::{CurrentScreen, EditingField, EntryCreation},
status::{AppStatus, CurrentScreen, EditingField, EntryValError},
};
pub struct AppState {
@@ -16,11 +16,12 @@ pub struct AppState {
pub fromPort: String,
pub toIP: String,
pub toPort: String,
pub screen: CurrentScreen,
pub currentlyEditing: Option<EditingField>,
pub screen: CurrentScreen,
pub entries: Vec<Entry>,
pub confDir: String,
pub tableState: TableState,
pub appStatus: AppStatus,
}
impl AppState {
@@ -36,10 +37,11 @@ impl AppState {
entries: settings.entries,
confDir,
tableState: TableState::default().with_selected(0),
appStatus: AppStatus::Welcome,
}
}
pub fn store(&mut self) -> EntryCreation {
pub fn store(&mut self) -> EntryValError {
match Entry::new(
self.fromIP.clone(),
self.toIP.clone(),
@@ -53,11 +55,10 @@ impl AppState {
self.fromPort = String::new();
self.toPort = String::new();
self.currentlyEditing = None;
self.tableState
.select(Some(self.entries.len() - 1 as usize));
EntryCreation::Success
self.tableState.select(Some(self.entries.len() - 1_usize));
EntryValError::NONE
}
_ => EntryCreation::PortValidationError,
Err(e) => e,
}
}

View File

@@ -13,8 +13,28 @@ pub enum EditingField {
ToPort,
}
pub enum EntryCreation {
Success,
PortValidationError,
IPValidationError,
pub enum EntryValError {
NONE,
ToPortValError,
FromPortValError,
ToIPValError,
FromIPValError,
}
pub enum AppStatus {
Welcome,
Editing,
Error(EntryValError),
Added,
Saved,
}
pub fn entryValError2Field(err: &EntryValError) -> EditingField {
match err {
EntryValError::ToPortValError => EditingField::ToPort,
EntryValError::FromPortValError => EditingField::FromPort,
EntryValError::ToIPValError => EditingField::ToIP,
EntryValError::FromIPValError => EditingField::FromIP,
EntryValError::NONE => EditingField::FromIP,
}
}

View File

@@ -16,7 +16,9 @@ use ratatui::crossterm::terminal::{
use ratatui::prelude::{Backend, CrosstermBackend};
use std::io;
use crate::app::status::{CurrentScreen, EditingField};
use crate::app::status::{
AppStatus, CurrentScreen, EditingField, EntryValError, entryValError2Field,
};
fn main() -> Result<()> {
enable_raw_mode()?;
@@ -64,8 +66,8 @@ fn runApp<B: Backend>(app: &mut AppState, terminal: &mut Terminal<B>) -> Result<
_ => {}
},
CurrentScreen::Delete => match key.code {
KeyCode::Up => app.nextRow(),
KeyCode::Down => app.prevRow(),
KeyCode::Up => app.prevRow(),
KeyCode::Down => app.nextRow(),
KeyCode::Enter => app.delCur(),
KeyCode::Esc => app.screen = CurrentScreen::Main,
_ => {}
@@ -74,14 +76,15 @@ fn runApp<B: Backend>(app: &mut AppState, terminal: &mut Terminal<B>) -> Result<
KeyCode::Char('a') => {
app.screen = CurrentScreen::Add;
app.currentlyEditing = Some(EditingField::FromIP);
app.appStatus = AppStatus::Editing;
}
KeyCode::Char('q') | KeyCode::F(10) | KeyCode::Esc => {
app.screen = CurrentScreen::Exit
}
KeyCode::Char('s') | KeyCode::F(2) => app.screen = CurrentScreen::Settings,
KeyCode::Char('d') => app.screen = CurrentScreen::Delete,
KeyCode::Up => app.nextRow(),
KeyCode::Down => app.prevRow(),
KeyCode::Up => app.prevRow(),
KeyCode::Down => app.nextRow(),
_ => {}
},
CurrentScreen::Add => match (key.modifiers, key.code) {
@@ -89,9 +92,18 @@ fn runApp<B: Backend>(app: &mut AppState, terminal: &mut Terminal<B>) -> Result<
if let Some(eF) = &app.currentlyEditing {
match eF {
EditingField::ToPort => {
app.store();
app.screen = CurrentScreen::Main;
app.currentlyEditing = None;
let res = app.store();
match res {
EntryValError::NONE => {
app.screen = CurrentScreen::Main;
app.currentlyEditing = None;
app.appStatus = AppStatus::Added;
}
_ => {
app.currentlyEditing = Some(entryValError2Field(&res));
app.appStatus = AppStatus::Error(res);
}
}
}
_ => app.nextField(),
}

View File

@@ -10,7 +10,7 @@ use ratatui::{
widgets::{Block, Borders, Cell, Paragraph, Row, Table, Wrap},
};
use crate::app::status::CurrentScreen;
use crate::app::status::{AppStatus, CurrentScreen, EntryValError};
use crate::app::{AppState, status::EditingField};
use crate::ui::centeredRect::centered_rect;
use crate::ui::textHints::hints;
@@ -177,7 +177,7 @@ pub fn ui(frame: &mut Frame, app: &mut AppState) {
}
CurrentScreen::Add => {
borderColor = Color::LightGreen;
Span::styled("Add entry", Style::default().fg(Color::Green))
Span::styled("Add Window", Style::default().fg(Color::Green))
}
CurrentScreen::Exit => {
borderColor = Color::LightRed;
@@ -188,26 +188,43 @@ pub fn ui(frame: &mut Frame, app: &mut AppState) {
Span::styled("Settings", Style::default().fg(Color::Blue))
}
CurrentScreen::Delete => {
borderColor = Color::LightMagenta;
Span::styled("Delete Selection", Style::default().fg(Color::Magenta))
borderColor = Color::Magenta;
Span::styled("Delete", Style::default().fg(Color::Magenta))
}
}
.to_owned(),
Span::styled(" | ", Style::default().fg(Color::White)),
{
if let Some(editing) = &app.currentlyEditing {
let curEdit = match editing {
EditingField::FromIP => "From IP",
EditingField::ToIP => "To IP",
EditingField::FromPort => "From Port",
EditingField::ToPort => "To Port",
};
Span::styled(
format!("Editing: {curEdit}"),
Style::default().fg(Color::Green),
)
} else {
Span::styled("Not Editing", Style::default().fg(Color::DarkGray))
match &app.appStatus {
AppStatus::Welcome => Span::styled("Welcome", Style::default().fg(Color::White)),
AppStatus::Added => Span::styled("Added", Style::default().fg(Color::Green)),
AppStatus::Editing => {
if let Some(editing) = &app.currentlyEditing {
let curEdit = match editing {
EditingField::FromIP => "From IP",
EditingField::ToIP => "To IP",
EditingField::FromPort => "From Port",
EditingField::ToPort => "To Port",
};
Span::styled(
format!("Editing: {curEdit}"),
Style::default().fg(Color::Green),
)
} else {
Span::styled("Not Editing", Style::default().fg(Color::White))
}
}
AppStatus::Error(e) => {
let errString = match e {
EntryValError::ToPortValError => "To Port Invalid",
EntryValError::FromPortValError => "From Port Invalid",
EntryValError::ToIPValError => "To IP Invalid",
EntryValError::FromIPValError => "From IP Invalid",
EntryValError::NONE => "",
};
Span::styled(errString, Style::default().fg(Color::Red))
}
AppStatus::Saved => Span::styled("", Style::default()),
}
},
];

View File

@@ -8,18 +8,20 @@ pub mod hints {
Text::from(vec![
Line::from("(a) Add entry").style(Style::default().fg(Color::Green)),
Line::from("(d) Delete entry").style(Style::default().fg(Color::Magenta)),
Line::from("(↑/↓) Scroll").style(Style::default().fg(Color::White)),
Line::from("(s) Save").style(Style::default().fg(Color::Yellow)),
Line::from("(q) Quit").style(Style::default().fg(Color::Red)),
])
}
pub fn addHints<'a>() -> Text<'a> {
Text::from(vec![
Line::from("(l) 127.0.0.1"),
Line::from("(o) 0.0.0.0"),
Line::from("(enter) next field"),
Line::from("(c) clear"),
Line::from("(C) clear all"),
Line::from("(esc) main menu").style(Style::default().fg(Color::LightBlue)),
Line::from("(l) 127.0.0.1").style(Style::default().fg(Color::White)),
Line::from("(o) 0.0.0.0").style(Style::default().fg(Color::White)),
Line::from("(c) Clear field").style(Style::default().fg(Color::White)),
Line::from("(C) Clear all fields").style(Style::default().fg(Color::White)),
Line::from("(enter) Next field/Save"),
Line::from("(esc) Main menu").style(Style::default().fg(Color::LightBlue)),
])
}
@@ -32,8 +34,7 @@ pub mod hints {
pub fn delHints<'a>() -> Text<'a> {
Text::from(vec![
Line::from("(up) move up"),
Line::from("(down) move down"),
Line::from("(↑/↓) Scroll").style(Style::default().fg(Color::White)),
Line::from("(enter) delete selection").style(Style::default().fg(Color::Magenta)),
Line::from("(esc) main menu").style(Style::default().fg(Color::LightBlue)),
])