From 667eb4809d69355f1f517e177cb49df4453a5f5a Mon Sep 17 00:00:00 2001 From: filipriec Date: Fri, 23 May 2025 15:22:21 +0200 Subject: [PATCH] compiled but the readonly and edit mode is not working --- client/src/components/admin.rs | 2 + client/src/functions/modes/edit.rs | 1 + .../src/functions/modes/edit/add_logic_e.rs | 277 ++++++++++++++++++ client/src/functions/modes/read_only.rs | 1 + .../functions/modes/read_only/add_logic_ro.rs | 244 +++++++++++++++ client/src/modes/canvas/edit.rs | 48 ++- client/src/modes/canvas/read_only.rs | 32 +- client/src/modes/handlers/event.rs | 37 ++- client/src/modes/highlight/highlight.rs | 7 +- client/src/ui/handlers/render.rs | 11 + 10 files changed, 643 insertions(+), 17 deletions(-) create mode 100644 client/src/functions/modes/edit/add_logic_e.rs create mode 100644 client/src/functions/modes/read_only/add_logic_ro.rs diff --git a/client/src/components/admin.rs b/client/src/components/admin.rs index 6cdfafd..46bccbe 100644 --- a/client/src/components/admin.rs +++ b/client/src/components/admin.rs @@ -2,7 +2,9 @@ pub mod admin_panel; pub mod admin_panel_admin; pub mod add_table; +pub mod add_logic; pub use admin_panel::*; pub use admin_panel_admin::*; pub use add_table::*; +pub use add_logic::*; diff --git a/client/src/functions/modes/edit.rs b/client/src/functions/modes/edit.rs index 3196927..3bda6b2 100644 --- a/client/src/functions/modes/edit.rs +++ b/client/src/functions/modes/edit.rs @@ -3,3 +3,4 @@ pub mod form_e; pub mod auth_e; pub mod add_table_e; +pub mod add_logic_e; diff --git a/client/src/functions/modes/edit/add_logic_e.rs b/client/src/functions/modes/edit/add_logic_e.rs new file mode 100644 index 0000000..f16a6ba --- /dev/null +++ b/client/src/functions/modes/edit/add_logic_e.rs @@ -0,0 +1,277 @@ +// src/functions/modes/edit/add_logic_e.rs +use crate::state::pages::add_logic::AddLogicState; // Changed +use crate::state::pages::canvas_state::CanvasState; +use crossterm::event::{KeyCode, KeyEvent}; +use anyhow::Result; + +// Word navigation helpers (get_char_type, find_next_word_start, etc.) +// can be kept as they are generic. +#[derive(PartialEq)] +enum CharType { + Whitespace, + Alphanumeric, + Punctuation, +} + +fn get_char_type(c: char) -> CharType { + if c.is_whitespace() { CharType::Whitespace } + else if c.is_alphanumeric() { CharType::Alphanumeric } + else { CharType::Punctuation } +} + +fn find_next_word_start(text: &str, current_pos: usize) -> usize { + let chars: Vec = text.chars().collect(); + let len = chars.len(); + if len == 0 || current_pos >= len { return len; } + let mut pos = current_pos; + let initial_type = get_char_type(chars[pos]); + while pos < len && get_char_type(chars[pos]) == initial_type { pos += 1; } + while pos < len && get_char_type(chars[pos]) == CharType::Whitespace { pos += 1; } + pos +} + +fn find_word_end(text: &str, current_pos: usize) -> usize { + let chars: Vec = text.chars().collect(); + let len = chars.len(); + if len == 0 { return 0; } + let mut pos = current_pos.min(len - 1); + if get_char_type(chars[pos]) == CharType::Whitespace { + pos = find_next_word_start(text, pos); + } + if pos >= len { return len.saturating_sub(1); } + let word_type = get_char_type(chars[pos]); + while pos < len && get_char_type(chars[pos]) == word_type { pos += 1; } + pos.saturating_sub(1).min(len.saturating_sub(1)) +} + +fn find_prev_word_start(text: &str, current_pos: usize) -> usize { + let chars: Vec = text.chars().collect(); + if chars.is_empty() || current_pos == 0 { return 0; } + let mut pos = current_pos.saturating_sub(1); + while pos > 0 && get_char_type(chars[pos]) == CharType::Whitespace { pos -= 1; } + if pos == 0 && get_char_type(chars[pos]) == CharType::Whitespace { return 0; } + let word_type = get_char_type(chars[pos]); + while pos > 0 && get_char_type(chars[pos - 1]) == word_type { pos -= 1; } + pos +} + +fn find_prev_word_end(text: &str, current_pos: usize) -> usize { + let chars: Vec = text.chars().collect(); + let len = chars.len(); + if len == 0 || current_pos == 0 { return 0; } + let mut pos = current_pos.saturating_sub(1); + while pos > 0 && get_char_type(chars[pos]) == CharType::Whitespace { pos -= 1; } + if pos == 0 && get_char_type(chars[pos]) == CharType::Whitespace { return 0; } + if pos == 0 && get_char_type(chars[pos]) != CharType::Whitespace { return 0; } + let word_type = get_char_type(chars[pos]); + while pos > 0 && get_char_type(chars[pos - 1]) == word_type { pos -= 1; } + while pos > 0 && get_char_type(chars[pos - 1]) == CharType::Whitespace { pos -= 1; } + if pos > 0 { pos - 1 } else { 0 } +} + +/// Executes edit actions for the AddLogic view canvas. +pub async fn execute_edit_action( + action: &str, + key: KeyEvent, + state: &mut AddLogicState, // Changed + ideal_cursor_column: &mut usize, +) -> Result { + match action { + "insert_char" => { + if let KeyCode::Char(c) = key.code { + let cursor_pos = state.current_cursor_pos(); + let field_value = state.get_current_input_mut(); + let mut chars: Vec = field_value.chars().collect(); + if cursor_pos <= chars.len() { + chars.insert(cursor_pos, c); + *field_value = chars.into_iter().collect(); + state.set_current_cursor_pos(cursor_pos + 1); + state.set_has_unsaved_changes(true); + *ideal_cursor_column = state.current_cursor_pos(); + } + } else { + return Ok("Error: insert_char called without a char key.".to_string()); + } + Ok("".to_string()) + } + "delete_char_backward" => { + if state.current_cursor_pos() > 0 { + let cursor_pos = state.current_cursor_pos(); + let field_value = state.get_current_input_mut(); + let mut chars: Vec = field_value.chars().collect(); + if cursor_pos <= chars.len() { + chars.remove(cursor_pos - 1); + *field_value = chars.into_iter().collect(); + let new_pos = cursor_pos - 1; + state.set_current_cursor_pos(new_pos); + state.set_has_unsaved_changes(true); + *ideal_cursor_column = new_pos; + } + } + Ok("".to_string()) + } + "delete_char_forward" => { + let cursor_pos = state.current_cursor_pos(); + let field_value = state.get_current_input_mut(); + let mut chars: Vec = field_value.chars().collect(); + if cursor_pos < chars.len() { + chars.remove(cursor_pos); + *field_value = chars.into_iter().collect(); + state.set_has_unsaved_changes(true); + *ideal_cursor_column = cursor_pos; + } + Ok("".to_string()) + } + "next_field" => { + let num_fields = AddLogicState::INPUT_FIELD_COUNT; // Changed + if num_fields > 0 { + let current_field = state.current_field(); + let last_field_index = num_fields - 1; + if current_field < last_field_index { // Prevent cycling + state.set_current_field(current_field + 1); + } + let current_input = state.get_current_input(); + let max_pos = current_input.len(); + state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos)); + } + Ok("".to_string()) + } + "prev_field" => { + let num_fields = AddLogicState::INPUT_FIELD_COUNT; // Changed + if num_fields > 0 { + let current_field = state.current_field(); + if current_field > 0 { // Prevent cycling + state.set_current_field(current_field - 1); + } + let current_input = state.get_current_input(); + let max_pos = current_input.len(); + state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos)); + } + Ok("".to_string()) + } + "move_left" => { + let new_pos = state.current_cursor_pos().saturating_sub(1); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + Ok("".to_string()) + } + "move_right" => { + let current_input = state.get_current_input(); + let current_pos = state.current_cursor_pos(); + if current_pos < current_input.len() { + let new_pos = current_pos + 1; + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + } + Ok("".to_string()) + } + "move_up" => { // In edit mode, up/down usually means prev/next field + let current_field = state.current_field(); + if current_field > 0 { + let new_field = current_field - 1; + state.set_current_field(new_field); + let current_input = state.get_current_input(); + let max_pos = current_input.len(); + state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos)); + } + Ok("".to_string()) + } + "move_down" => { // In edit mode, up/down usually means prev/next field + let num_fields = AddLogicState::INPUT_FIELD_COUNT; // Changed + if num_fields > 0 { + let current_field = state.current_field(); + let last_field_index = num_fields - 1; + if current_field < last_field_index { + let new_field = current_field + 1; + state.set_current_field(new_field); + let current_input = state.get_current_input(); + let max_pos = current_input.len(); + state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos)); + } + } + Ok("".to_string()) + } + "move_line_start" => { + state.set_current_cursor_pos(0); + *ideal_cursor_column = 0; + Ok("".to_string()) + } + "move_line_end" => { + let current_input = state.get_current_input(); + let new_pos = current_input.len(); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + Ok("".to_string()) + } + "move_first_line" => { + if AddLogicState::INPUT_FIELD_COUNT > 0 { // Changed + state.set_current_field(0); + let current_input = state.get_current_input(); + let max_pos = current_input.len(); + state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos)); + } + Ok("".to_string()) + } + "move_last_line" => { + let num_fields = AddLogicState::INPUT_FIELD_COUNT; // Changed + if num_fields > 0 { + let new_field = num_fields - 1; + state.set_current_field(new_field); + let current_input = state.get_current_input(); + let max_pos = current_input.len(); + state.set_current_cursor_pos((*ideal_cursor_column).min(max_pos)); + } + Ok("".to_string()) + } + "move_word_next" => { + let current_input = state.get_current_input(); + if !current_input.is_empty() { + let new_pos = find_next_word_start(current_input, state.current_cursor_pos()); + let final_pos = new_pos.min(current_input.len()); + state.set_current_cursor_pos(final_pos); + *ideal_cursor_column = final_pos; + } + Ok("".to_string()) + } + "move_word_end" => { + let current_input = state.get_current_input(); + if !current_input.is_empty() { + let current_pos = state.current_cursor_pos(); + let new_pos = find_word_end(current_input, current_pos); + let final_pos = if new_pos == current_pos && current_pos < current_input.len() { // Ensure not to go past end + find_word_end(current_input, current_pos + 1) + } else { + new_pos + }; + let max_valid_index = current_input.len(); // Allow cursor at end + let clamped_pos = final_pos.min(max_valid_index); + state.set_current_cursor_pos(clamped_pos); + *ideal_cursor_column = clamped_pos; + } + Ok("".to_string()) + } + "move_word_prev" => { + let current_input = state.get_current_input(); + if !current_input.is_empty() { + let new_pos = find_prev_word_start(current_input, state.current_cursor_pos()); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + } + Ok("".to_string()) + } + "move_word_end_prev" => { + let current_input = state.get_current_input(); + if !current_input.is_empty() { + let new_pos = find_prev_word_end(current_input, state.current_cursor_pos()); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + } + Ok("".to_string()) + } + "exit_edit_mode" | "save" | "revert" => { + Ok("Action handled by main loop".to_string()) + } + _ => Ok(format!("Unknown or unhandled edit action: {}", action)), + } +} + diff --git a/client/src/functions/modes/read_only.rs b/client/src/functions/modes/read_only.rs index 038efcf..77b3f60 100644 --- a/client/src/functions/modes/read_only.rs +++ b/client/src/functions/modes/read_only.rs @@ -3,3 +3,4 @@ pub mod auth_ro; pub mod form_ro; pub mod add_table_ro; +pub mod add_logic_ro; diff --git a/client/src/functions/modes/read_only/add_logic_ro.rs b/client/src/functions/modes/read_only/add_logic_ro.rs new file mode 100644 index 0000000..fd9421f --- /dev/null +++ b/client/src/functions/modes/read_only/add_logic_ro.rs @@ -0,0 +1,244 @@ +// src/functions/modes/read_only/add_logic_ro.rs +use crate::config::binds::key_sequences::KeySequenceTracker; +use crate::state::pages::add_logic::AddLogicState; // Changed +use crate::state::pages::canvas_state::CanvasState; +use crate::state::app::state::AppState; +use anyhow::Result; + +// Word navigation helpers (get_char_type, find_next_word_start, etc.) +// can be kept as they are generic. +#[derive(PartialEq)] +enum CharType { + Whitespace, + Alphanumeric, + Punctuation, +} + +fn get_char_type(c: char) -> CharType { + if c.is_whitespace() { CharType::Whitespace } + else if c.is_alphanumeric() { CharType::Alphanumeric } + else { CharType::Punctuation } +} + +fn find_next_word_start(text: &str, current_pos: usize) -> usize { + let chars: Vec = text.chars().collect(); + let len = chars.len(); + if len == 0 || current_pos >= len { return len; } + let mut pos = current_pos; + let initial_type = get_char_type(chars[pos]); + while pos < len && get_char_type(chars[pos]) == initial_type { pos += 1; } + while pos < len && get_char_type(chars[pos]) == CharType::Whitespace { pos += 1; } + pos +} + +fn find_word_end(text: &str, current_pos: usize) -> usize { + let chars: Vec = text.chars().collect(); + let len = chars.len(); + if len == 0 { return 0; } + let mut pos = current_pos.min(len - 1); + if get_char_type(chars[pos]) == CharType::Whitespace { + pos = find_next_word_start(text, pos); + } + if pos >= len { return len.saturating_sub(1); } + let word_type = get_char_type(chars[pos]); + while pos < len && get_char_type(chars[pos]) == word_type { pos += 1; } + pos.saturating_sub(1).min(len.saturating_sub(1)) +} + +fn find_prev_word_start(text: &str, current_pos: usize) -> usize { + let chars: Vec = text.chars().collect(); + if chars.is_empty() || current_pos == 0 { return 0; } + let mut pos = current_pos.saturating_sub(1); + while pos > 0 && get_char_type(chars[pos]) == CharType::Whitespace { pos -= 1; } + if pos == 0 && get_char_type(chars[pos]) == CharType::Whitespace { return 0; } + let word_type = get_char_type(chars[pos]); + while pos > 0 && get_char_type(chars[pos - 1]) == word_type { pos -= 1; } + pos +} + +fn find_prev_word_end(text: &str, current_pos: usize) -> usize { + let prev_start = find_prev_word_start(text, current_pos); + if prev_start == 0 { return 0; } + find_word_end(text, prev_start.saturating_sub(1)) +} + + +/// Executes read-only actions for the AddLogic view canvas. +pub async fn execute_action( + action: &str, + app_state: &mut AppState, + state: &mut AddLogicState, // Changed + ideal_cursor_column: &mut usize, + key_sequence_tracker: &mut KeySequenceTracker, + command_message: &mut String, +) -> Result { + match action { + "move_up" => { + key_sequence_tracker.reset(); + let num_fields = AddLogicState::INPUT_FIELD_COUNT; // Changed + if num_fields == 0 { return Ok("No fields.".to_string()); } + let current_field = state.current_field(); + + if current_field > 0 { + let new_field = current_field - 1; + state.set_current_field(new_field); + let current_input = state.get_current_input(); + let max_cursor_pos = if current_input.is_empty() { 0 } else { current_input.len().saturating_sub(1) }; + let new_pos = (*ideal_cursor_column).min(max_cursor_pos); + state.set_current_cursor_pos(new_pos); + } else { + // Moving up from the first field (InputLogicName) + app_state.ui.focus_outside_canvas = true; + // Focus should go to the element logically above the canvas. + // Based on AddLogicFocus, this might be CancelButton or another element. + // For AddLogic, let's assume it's CancelButton, similar to AddTable. + state.current_focus = crate::state::pages::add_logic::AddLogicFocus::CancelButton; // Changed + key_sequence_tracker.reset(); + return Ok("Focus moved above canvas".to_string()); + } + Ok("".to_string()) + } + "move_down" => { + key_sequence_tracker.reset(); + let num_fields = AddLogicState::INPUT_FIELD_COUNT; // Changed + if num_fields == 0 { return Ok("No fields.".to_string()); } + let current_field = state.current_field(); + let last_field_index = num_fields - 1; + + if current_field < last_field_index { + let new_field = current_field + 1; + state.set_current_field(new_field); + let current_input = state.get_current_input(); + let max_cursor_pos = if current_input.is_empty() { 0 } else { current_input.len().saturating_sub(1) }; + let new_pos = (*ideal_cursor_column).min(max_cursor_pos); + state.set_current_cursor_pos(new_pos); + } else { + // Moving down from the last field (InputDescription) + app_state.ui.focus_outside_canvas = true; + // Focus should go to the element logically below the canvas. + // This is likely InputScriptContent or SaveButton. + // The add_logic_nav.rs handles transitions to InputScriptContent. + // If moving from canvas directly to buttons, it would be SaveButton. + state.current_focus = crate::state::pages::add_logic::AddLogicFocus::InputScriptContent; // Or SaveButton + key_sequence_tracker.reset(); + return Ok("Focus moved to script/button area".to_string()); + } + Ok("".to_string()) + } + "move_first_line" => { + key_sequence_tracker.reset(); + if AddLogicState::INPUT_FIELD_COUNT > 0 { // Changed + state.set_current_field(0); + let current_input = state.get_current_input(); + let max_cursor_pos = if current_input.is_empty() { 0 } else { current_input.len().saturating_sub(1) }; + let new_pos = (*ideal_cursor_column).min(max_cursor_pos); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + } + Ok("".to_string()) + } + "move_last_line" => { + key_sequence_tracker.reset(); + let num_fields = AddLogicState::INPUT_FIELD_COUNT; // Changed + if num_fields > 0 { + let last_field_index = num_fields - 1; + state.set_current_field(last_field_index); + let current_input = state.get_current_input(); + let max_cursor_pos = if current_input.is_empty() { 0 } else { current_input.len().saturating_sub(1) }; + let new_pos = (*ideal_cursor_column).min(max_cursor_pos); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + } + Ok("".to_string()) + } + "move_left" => { + let current_pos = state.current_cursor_pos(); + let new_pos = current_pos.saturating_sub(1); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + Ok("".to_string()) + } + "move_right" => { + let current_input = state.get_current_input(); + let current_pos = state.current_cursor_pos(); + if !current_input.is_empty() && current_pos < current_input.len().saturating_sub(1) { + let new_pos = current_pos + 1; + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + } + Ok("".to_string()) + } + "move_word_next" => { + let current_input = state.get_current_input(); + if !current_input.is_empty() { + let new_pos = find_next_word_start(current_input, state.current_cursor_pos()); + let final_pos = new_pos.min(current_input.len().saturating_sub(1)); + state.set_current_cursor_pos(final_pos); + *ideal_cursor_column = final_pos; + } + Ok("".to_string()) + } + "move_word_end" => { + let current_input = state.get_current_input(); + if !current_input.is_empty() { + let current_pos = state.current_cursor_pos(); + let new_pos = find_word_end(current_input, current_pos); + let final_pos = if new_pos == current_pos && current_pos < current_input.len().saturating_sub(1) { + find_word_end(current_input, current_pos + 1) + } else { + new_pos + }; + let max_valid_index = current_input.len().saturating_sub(1); + let clamped_pos = final_pos.min(max_valid_index); + state.set_current_cursor_pos(clamped_pos); + *ideal_cursor_column = clamped_pos; + } + Ok("".to_string()) + } + "move_word_prev" => { + let current_input = state.get_current_input(); + if !current_input.is_empty() { + let new_pos = find_prev_word_start(current_input, state.current_cursor_pos()); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + } + Ok("".to_string()) + } + "move_word_end_prev" => { + let current_input = state.get_current_input(); + if !current_input.is_empty() { + let new_pos = find_prev_word_end(current_input, state.current_cursor_pos()); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + } + Ok("".to_string()) + } + "move_line_start" => { + state.set_current_cursor_pos(0); + *ideal_cursor_column = 0; + Ok("".to_string()) + } + "move_line_end" => { + let current_input = state.get_current_input(); + if !current_input.is_empty() { + let new_pos = current_input.len().saturating_sub(1); + state.set_current_cursor_pos(new_pos); + *ideal_cursor_column = new_pos; + } else { + state.set_current_cursor_pos(0); + *ideal_cursor_column = 0; + } + Ok("".to_string()) + } + "enter_edit_mode_before" | "enter_edit_mode_after" | "enter_command_mode" | "exit_highlight_mode" => { + key_sequence_tracker.reset(); + Ok("Mode change handled by main loop".to_string()) + } + _ => { + key_sequence_tracker.reset(); + command_message.clear(); + Ok(format!("Unknown read-only action: {}", action)) + }, + } +} + diff --git a/client/src/modes/canvas/edit.rs b/client/src/modes/canvas/edit.rs index ef1eae3..6959dee 100644 --- a/client/src/modes/canvas/edit.rs +++ b/client/src/modes/canvas/edit.rs @@ -5,11 +5,12 @@ use crate::state::pages::{ auth::{LoginState, RegisterState}, canvas_state::CanvasState, }; +use crate::state::pages::add_logic::AddLogicState; use crate::state::pages::form::FormState; use crate::state::pages::add_table::AddTableState; +use crate::state::pages::admin::AdminState; use crate::modes::handlers::event::EventOutcome; -use crate::functions::modes::edit::{auth_e, form_e}; -use crate::functions::modes::edit::add_table_e; +use crate::functions::modes::edit::{add_logic_e, auth_e, form_e, add_table_e}; use crate::state::app::state::AppState; use anyhow::Result; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; @@ -26,7 +27,7 @@ pub async fn handle_edit_event( form_state: &mut FormState, login_state: &mut LoginState, register_state: &mut RegisterState, - add_table_state: &mut AddTableState, + admin_state: &mut AdminState, ideal_cursor_column: &mut usize, current_position: &mut u64, total_count: u64, @@ -73,6 +74,11 @@ pub async fn handle_edit_event( "Action '{}' not fully implemented for Add Table view here.", action ) + } else if app_state.ui.show_add_logic { + format!( + "Action '{}' not fully implemented for Add Logic view here.", + action + ) } else { let outcome = form_e::execute_common_action( action, @@ -101,14 +107,14 @@ pub async fn handle_edit_event( .as_deref() { // Handle enter_decider first if action == "enter_decider" { - let effective_action = if app_state.ui.show_register - && register_state.in_suggestion_mode + let effective_action = if app_state.ui.show_register + && register_state.in_suggestion_mode && register_state.current_field() == 4 { "select_suggestion" } else { "next_field" }; - + let msg = if app_state.ui.show_login { auth_e::execute_edit_action( effective_action, @@ -121,7 +127,15 @@ pub async fn handle_edit_event( add_table_e::execute_edit_action( effective_action, key, - add_table_state, + &mut admin_state.add_table_state, + ideal_cursor_column, + ) + .await? + } else if app_state.ui.show_add_logic { + add_logic_e::execute_edit_action( + effective_action, + key, + &mut admin_state.add_logic_state, ideal_cursor_column, ) .await? @@ -209,7 +223,15 @@ pub async fn handle_edit_event( add_table_e::execute_edit_action( action, key, - add_table_state, + &mut admin_state.add_table_state, + ideal_cursor_column, + ) + .await? + } else if app_state.ui.show_add_logic { + add_logic_e::execute_edit_action( + action, + key, + &mut admin_state.add_logic_state, ideal_cursor_column, ) .await? @@ -252,7 +274,15 @@ pub async fn handle_edit_event( add_table_e::execute_edit_action( "insert_char", key, - add_table_state, + &mut admin_state.add_table_state, + ideal_cursor_column, + ) + .await? + } else if app_state.ui.show_add_logic { + add_logic_e::execute_edit_action( + "insert_char", + key, + &mut admin_state.add_logic_state, ideal_cursor_column, ) .await? diff --git a/client/src/modes/canvas/read_only.rs b/client/src/modes/canvas/read_only.rs index 8b9638e..125b602 100644 --- a/client/src/modes/canvas/read_only.rs +++ b/client/src/modes/canvas/read_only.rs @@ -6,9 +6,10 @@ use crate::services::grpc_client::GrpcClient; use crate::state::pages::{canvas_state::CanvasState, auth::RegisterState}; use crate::state::pages::auth::LoginState; use crate::state::pages::form::FormState; +use crate::state::pages::add_logic::AddLogicState; use crate::state::pages::add_table::AddTableState; use crate::state::app::state::AppState; -use crate::functions::modes::read_only::{auth_ro, form_ro, add_table_ro}; +use crate::functions::modes::read_only::{add_logic_ro, auth_ro, form_ro, add_table_ro}; use crossterm::event::KeyEvent; use anyhow::Result; @@ -20,6 +21,7 @@ pub async fn handle_read_only_event( login_state: &mut LoginState, register_state: &mut RegisterState, add_table_state: &mut AddTableState, + add_logic_state: &mut AddLogicState, key_sequence_tracker: &mut KeySequenceTracker, current_position: &mut u64, total_count: u64, @@ -37,6 +39,7 @@ pub async fn handle_read_only_event( if config.is_enter_edit_mode_after(key.code, key.modifiers) { // Determine target state to adjust cursor let target_state: &mut dyn CanvasState = if app_state.ui.show_login { login_state } + else if app_state.ui.show_add_logic { add_logic_state } else if app_state.ui.show_register { register_state } else if app_state.ui.show_add_table { add_table_state } else { form_state }; @@ -87,6 +90,15 @@ pub async fn handle_read_only_event( key_sequence_tracker, command_message, ).await? + } else if app_state.ui.show_add_logic { + add_logic_ro::execute_action( + action, + app_state, + add_logic_state, + ideal_cursor_column, + key_sequence_tracker, + command_message, + ).await? } else if app_state.ui.show_register{ auth_ro::execute_action( action, @@ -147,6 +159,15 @@ pub async fn handle_read_only_event( key_sequence_tracker, command_message, ).await? + } else if app_state.ui.show_add_logic { + add_logic_ro::execute_action( + action, + app_state, + add_logic_state, + ideal_cursor_column, + key_sequence_tracker, + command_message, + ).await? } else if app_state.ui.show_register { auth_ro::execute_action( action, @@ -206,6 +227,15 @@ pub async fn handle_read_only_event( key_sequence_tracker, command_message, ).await? + } else if app_state.ui.show_add_logic { + add_logic_ro::execute_action( + action, + app_state, + add_logic_state, + ideal_cursor_column, + key_sequence_tracker, + command_message, + ).await? } else if app_state.ui.show_register { auth_ro::execute_action( action, diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index 8904827..5f78b2f 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -42,6 +42,7 @@ use crate::tui::functions::common::login::LoginResult; use crate::tui::functions::common::register::RegisterResult; use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender; use crate::functions::modes::navigation::add_logic_nav::SaveLogicResultSender; +use crate::functions::modes::navigation::add_logic_nav; #[derive(Debug, Clone, PartialEq, Eq)] pub enum EventOutcome { @@ -118,6 +119,7 @@ impl EventHandler { else if ui.show_login { AppView::Login } else if ui.show_register { AppView::Register } else if ui.show_admin { AppView::Admin } + else if ui.show_add_logic { AppView::AddLogic } else if ui.show_add_table { AppView::AddTable } else if ui.show_form { let form_name = app_state.selected_profile.clone().unwrap_or_else(|| "Data Form".to_string()); @@ -195,6 +197,26 @@ impl EventHandler { return Ok(EventOutcome::Ok(self.command_message.clone())); } } + // --- Add Logic Page Navigation --- + if app_state.ui.show_add_logic { + let client_clone = grpc_client.clone(); + let sender_clone = self.save_logic_result_sender.clone(); + + if add_logic_nav::handle_add_logic_navigation( + key, + config, + app_state, + &mut admin_state.add_logic_state, + &mut self.is_edit_mode, + buffer_state, + client_clone, + sender_clone, + &mut self.command_message, + ) { + return Ok(EventOutcome::Ok(self.command_message.clone())); + } + } + // --- Add Table Page Navigation --- if app_state.ui.show_add_table { let client_clone = grpc_client.clone(); @@ -379,6 +401,7 @@ impl EventHandler { login_state, register_state, &mut admin_state.add_table_state, + &mut admin_state.add_logic_state, &mut self.key_sequence_tracker, current_position, total_count, @@ -413,9 +436,15 @@ impl EventHandler { let (_should_exit, message) = read_only::handle_read_only_event( app_state, key, config, form_state, login_state, - register_state, &mut admin_state.add_table_state, &mut self.key_sequence_tracker, - current_position, total_count, grpc_client, - &mut self.command_message, &mut self.edit_mode_cooldown, + register_state, + &mut admin_state.add_table_state, + &mut admin_state.add_logic_state, + &mut self.key_sequence_tracker, + current_position, + total_count, + grpc_client, + &mut self.command_message, + &mut self.edit_mode_cooldown, &mut self.ideal_cursor_column, ) .await?; @@ -461,7 +490,7 @@ impl EventHandler { form_state, login_state, register_state, - &mut admin_state.add_table_state, + admin_state, &mut self.ideal_cursor_column, current_position, total_count, diff --git a/client/src/modes/highlight/highlight.rs b/client/src/modes/highlight/highlight.rs index 103a326..023f2f4 100644 --- a/client/src/modes/highlight/highlight.rs +++ b/client/src/modes/highlight/highlight.rs @@ -6,7 +6,7 @@ use crate::config::binds::key_sequences::KeySequenceTracker; use crate::services::grpc_client::GrpcClient; use crate::state::app::state::AppState; use crate::state::pages::auth::{LoginState, RegisterState}; -use crate::state::pages::add_table::AddTableState; +use crate::state::pages::admin::AdminState; use crate::state::pages::form::FormState; use crate::modes::handlers::event::EventOutcome; use crate::modes::read_only; @@ -23,7 +23,7 @@ pub async fn handle_highlight_event( form_state: &mut FormState, login_state: &mut LoginState, register_state: &mut RegisterState, - add_table_state: &mut AddTableState, + admin_state: &mut AdminState, key_sequence_tracker: &mut KeySequenceTracker, current_position: &mut u64, total_count: u64, @@ -41,7 +41,8 @@ pub async fn handle_highlight_event( form_state, login_state, register_state, - add_table_state, + &mut admin_state.add_table_state, + &mut admin_state.add_logic_state, key_sequence_tracker, current_position, total_count, diff --git a/client/src/ui/handlers/render.rs b/client/src/ui/handlers/render.rs index a339ba7..c688908 100644 --- a/client/src/ui/handlers/render.rs +++ b/client/src/ui/handlers/render.rs @@ -9,6 +9,7 @@ use crate::components::{ handlers::sidebar::{self, calculate_sidebar_layout}, form::form::render_form, admin::render_add_table, + admin::add_logic::render_add_logic, auth::{login::render_login, register::render_register}, }; use crate::config::colors::themes::Theme; @@ -107,6 +108,16 @@ pub fn render_ui( login_state.current_field < 3, highlight_state, ); + } else if app_state.ui.show_add_logic { + render_add_logic( + f, + main_content_area, + theme, + app_state, + &mut admin_state.add_logic_state, + is_edit_mode, // Pass the general edit mode status + highlight_state, + ); } else if app_state.ui.show_login { render_login( f,