From 58f109ca9107f894a3c0ff0ceacaebd56afb7f2d Mon Sep 17 00:00:00 2001 From: filipriec Date: Fri, 29 Aug 2025 16:18:42 +0200 Subject: [PATCH] adding to have multiple forms pages --- client/src/buffer/functions.rs | 2 +- client/src/buffer/state.rs | 6 ++-- client/src/pages/forms/logic.rs | 8 +++--- client/src/pages/forms/ui.rs | 24 ++++++++-------- client/src/pages/routing/router.rs | 2 +- client/src/state/app/state.rs | 46 ++++++++++++++---------------- client/src/ui/handlers/ui.rs | 32 +++++++++++++-------- 7 files changed, 62 insertions(+), 58 deletions(-) diff --git a/client/src/buffer/functions.rs b/client/src/buffer/functions.rs index 578d457..1c22329 100644 --- a/client/src/buffer/functions.rs +++ b/client/src/buffer/functions.rs @@ -7,7 +7,7 @@ pub fn get_view_layer(view: &AppView) -> u8 { match view { AppView::Intro => 1, AppView::Login | AppView::Register | AppView::Admin | AppView::AddTable | AppView::AddLogic => 2, - AppView::Form | AppView::Scratch => 3, + AppView::Form(_) | AppView::Scratch => 3, } } diff --git a/client/src/buffer/state.rs b/client/src/buffer/state.rs index 2d67413..1ca0d90 100644 --- a/client/src/buffer/state.rs +++ b/client/src/buffer/state.rs @@ -8,7 +8,7 @@ pub enum AppView { Admin, AddTable, AddLogic, - Form, + Form(String), Scratch, } @@ -23,7 +23,7 @@ impl AppView { AppView::Admin => "Admin_Panel", AppView::AddTable => "Add_Table", AppView::AddLogic => "Add_Logic", - AppView::Form => "Form", + AppView::Form(_) => "Form", AppView::Scratch => "*scratch*", } } @@ -31,7 +31,7 @@ impl AppView { /// Returns the display name with dynamic context (for Form buffers) pub fn display_name_with_context(&self, current_table_name: Option<&str>) -> String { match self { - AppView::Form => { + AppView::Form(_) => { current_table_name .unwrap_or("Data Form") .to_string() diff --git a/client/src/pages/forms/logic.rs b/client/src/pages/forms/logic.rs index d4da864..c765cef 100644 --- a/client/src/pages/forms/logic.rs +++ b/client/src/pages/forms/logic.rs @@ -17,7 +17,7 @@ pub async fn save( app_state: &mut AppState, grpc_client: &mut GrpcClient, ) -> Result { - if let Some(fs) = app_state.form_state_mut() { + if let Some(fs) = app_state.active_form_state_mut(buffer_state) { if !fs.has_unsaved_changes { return Ok(SaveOutcome::NoChange); } @@ -62,7 +62,7 @@ pub async fn save( .context("Failed to post new table data")?; if response.success { - if let Some(fs) = app_state.form_state_mut() { + if let Some(fs) = app_state.active_form_state_mut(buffer_state) { fs.id = response.inserted_id; fs.total_count += 1; fs.current_position = fs.total_count; @@ -84,7 +84,7 @@ pub async fn save( .context("Failed to put (update) table data")?; if response.success { - if let Some(fs) = app_state.form_state_mut() { + if let Some(fs) = app_state.active_form_state_mut(buffer_state) { fs.has_unsaved_changes = false; } SaveOutcome::UpdatedExisting @@ -103,7 +103,7 @@ pub async fn revert( app_state: &mut AppState, grpc_client: &mut GrpcClient, ) -> Result { - if let Some(fs) = app_state.form_state_mut() { + if let Some(fs) = app_state.active_form_state_mut(buffer_state) { if fs.id == 0 || (fs.total_count > 0 && fs.current_position > fs.total_count) || (fs.total_count == 0 && fs.current_position == 1) diff --git a/client/src/pages/forms/ui.rs b/client/src/pages/forms/ui.rs index 9868e2e..6fb82f6 100644 --- a/client/src/pages/forms/ui.rs +++ b/client/src/pages/forms/ui.rs @@ -61,18 +61,18 @@ pub fn render_form_page( f.render_widget(count_para, main_layout[0]); // --- FORM RENDERING (Using persistent FormEditor) --- - if let Some(editor) = &app_state.form_editor { - let active_field_rect = render_canvas(f, main_layout[1], editor, theme); - - // --- SUGGESTIONS DROPDOWN --- - if let Some(active_rect) = active_field_rect { - render_suggestions_dropdown( - f, - main_layout[1], - active_rect, - &DefaultCanvasTheme, - editor, - ); + if let Some(AppView::Form(path)) = buffer_state.get_active_view() { + if let Some(editor) = app_state.form_editor.get(path) { + let active_field_rect = render_canvas(f, main_layout[1], editor, theme); + if let Some(active_rect) = active_field_rect { + render_suggestions_dropdown( + f, + main_layout[1], + active_rect, + &DefaultCanvasTheme, + editor, + ); + } } } } diff --git a/client/src/pages/routing/router.rs b/client/src/pages/routing/router.rs index 125f293..914660b 100644 --- a/client/src/pages/routing/router.rs +++ b/client/src/pages/routing/router.rs @@ -18,7 +18,7 @@ pub enum Page { Admin(AdminState), AddLogic(AddLogicState), AddTable(AddTableState), - Form(FormState), + Form(String), } pub struct Router { diff --git a/client/src/state/app/state.rs b/client/src/state/app/state.rs index b08dfb9..49d143e 100644 --- a/client/src/state/app/state.rs +++ b/client/src/state/app/state.rs @@ -60,7 +60,7 @@ pub struct AppState { // UI preferences pub ui: UiState, - pub form_editor: Option>, + pub form_editor: HashMap>, // key = "profile/table" #[cfg(feature = "ui-debug")] pub debug_state: Option, @@ -81,7 +81,7 @@ impl AppState { pending_table_structure_fetch: None, search_state: None, ui: UiState::default(), - form_editor: None, + form_editor: HashMap::new(), #[cfg(feature = "ui-debug")] debug_state: None, @@ -99,32 +99,28 @@ impl AppState { self.current_view_table_name = Some(table_name); } - pub fn init_form_editor(&mut self, form_state: FormState, config: &Config) { - let mut editor = FormEditor::new(form_state); - editor.set_keymap(config.build_canvas_keymap()); // inject keymap - self.form_editor = Some(editor); - } - - /// Replace the current form state and wrap it in a FormEditor with keymap - pub fn set_form_state(&mut self, form_state: FormState, config: &Config) { - let mut editor = FormEditor::new(form_state); - editor.set_keymap(config.build_canvas_keymap()); - self.form_editor = Some(editor); - } - - /// Immutable access to the underlying FormState - pub fn form_state(&self) -> Option<&FormState> { - self.form_editor.as_ref().map(|e| e.data_provider()) - } - - /// Mutable access to the underlying FormState - pub fn form_state_mut(&mut self) -> Option<&mut FormState> { - self.form_editor.as_mut().map(|e| e.data_provider_mut()) - } - pub fn is_canvas_edit_mode(&self) -> bool { matches!(self.form_editor.as_ref().map(|e| e.mode()), Some(canvas::AppMode::Edit)) } + + pub fn editor_for_path(&mut self, path: &str) -> Option<&mut FormEditor> { + self.form_editor.get_mut(path) + } + + pub fn form_state_for_path(&mut self, path: &str) -> Option<&mut FormState> { + self.form_editor.get_mut(path).map(|e| e.data_provider_mut()) + } + + pub fn ensure_form_editor(&mut self, path: &str, config: &Config, loader: F) + where + F: FnOnce() -> FormState, + { + if !self.form_editor.contains_key(path) { + let mut editor = FormEditor::new(loader()); + editor.set_keymap(config.build_canvas_keymap()); + self.form_editor.insert(path.to_string(), editor); + } + } } impl Default for UiState { diff --git a/client/src/ui/handlers/ui.rs b/client/src/ui/handlers/ui.rs index c72b144..434d65a 100644 --- a/client/src/ui/handlers/ui.rs +++ b/client/src/ui/handlers/ui.rs @@ -113,13 +113,15 @@ pub async fn run_ui() -> Result<()> { .collect(); // Replace local form_state with app_state.form_editor - app_state.set_form_state( - FormState::new(initial_profile.clone(), initial_table.clone(), initial_field_defs), - &config, - ); + let path = format!("{}/{}", initial_profile, initial_table); + app_state.ensure_form_editor(&path, &config, || { + FormState::new(initial_profile.clone(), initial_table.clone(), initial_field_defs) + }); + buffer_state.update_history(AppView::Form(path.clone())); + router.navigate(Page::Form(path)); // Fetch initial count using app_state accessor - if let Some(form_state) = app_state.form_state_mut() { + if let Some(form_state) = app_state.active_form_state_mut(&buffer_state) { UiService::fetch_and_set_table_count(&mut grpc_client, form_state) .await .context(format!( @@ -137,7 +139,9 @@ pub async fn run_ui() -> Result<()> { } if auto_logged_in { - buffer_state.history = vec![AppView::Form]; + let path = format!("{}/{}", initial_profile, initial_table); + buffer_state.history = vec![AppView::Form(path.clone())]; + router.navigate(Page::Form(path)); buffer_state.active_index = 0; info!("Initial view set to Form due to auto-login."); } @@ -150,7 +154,7 @@ pub async fn run_ui() -> Result<()> { let mut table_just_switched = false; loop { - let position_before_event = app_state.form_state() + let position_before_event = app_state.active_form_state_mut(&buffer_state) .map(|fs| fs.current_position) .unwrap_or(1); let mut event_processed = false; @@ -216,7 +220,7 @@ pub async fn run_ui() -> Result<()> { if !overlay_active { if let Page::Form(_) = &router.current { if !app_state.ui.focus_outside_canvas { - if let Some(editor) = app_state.form_editor.as_mut() { + if let Some(editor) = app_state.active_form_editor_mut(&buffer_state) { match editor.handle_key_event(*key_event) { KeyEventOutcome::Consumed(Some(msg)) => { event_handler.command_message = msg; @@ -725,11 +729,14 @@ pub async fn run_ui() -> Result<()> { // Workaround for borrow checker let current_dir = app_state.current_dir.clone(); - let form_state_clone = app_state.form_state().unwrap().clone(); + let form_state_clone = if let Page::Form(path) = &router.current { + app_state.form_state_for_path(path).cloned() + } else { + None + }; - terminal - .draw(|f| { - let mut temp_form_state = form_state_clone.clone(); + if let Some(form_state_clone) = form_state_clone { + terminal.draw(|f| { render_ui( f, &mut router, @@ -746,6 +753,7 @@ pub async fn run_ui() -> Result<()> { }) .context("Terminal draw call failed")?; needs_redraw = false; + } } let now = Instant::now();