diff --git a/client/src/components/admin/add_logic.rs b/client/src/components/admin/add_logic.rs index b3619d7..c8bc948 100644 --- a/client/src/components/admin/add_logic.rs +++ b/client/src/components/admin/add_logic.rs @@ -3,7 +3,7 @@ use crate::config::colors::themes::Theme; use crate::state::app::highlight::HighlightState; use crate::state::app::state::AppState; use crate::state::pages::add_logic::{AddLogicFocus, AddLogicState}; -use canvas::canvas::{render_canvas, CanvasState, HighlightState as CanvasHighlightState}; // Use canvas library +use canvas::{render_canvas_default, HighlightState as CanvasHighlightState}; use ratatui::{ layout::{Alignment, Constraint, Direction, Layout, Rect}, style::{Modifier, Style}, @@ -169,13 +169,10 @@ pub fn render_add_logic( ); let canvas_highlight_state = convert_highlight_state(highlight_state); - let active_field_rect = render_canvas( + let active_field_rect = render_canvas_default( f, canvas_area, - add_logic_state, // AddLogicState implements CanvasState - theme, // Theme implements CanvasTheme - is_edit_mode && focus_on_canvas_inputs, - &canvas_highlight_state, + add_logic_state, // will later be wrapped in FormEditor ); // --- Render Autocomplete for Target Column --- diff --git a/client/src/state/pages/add_logic.rs b/client/src/state/pages/add_logic.rs index b987d7d..8fb4a3a 100644 --- a/client/src/state/pages/add_logic.rs +++ b/client/src/state/pages/add_logic.rs @@ -1,7 +1,7 @@ // src/state/pages/add_logic.rs use crate::config::binds::config::{EditorConfig, EditorKeybindingMode}; -use canvas::canvas::{CanvasState, ActionContext, CanvasAction, AppMode}; use crate::components::common::text_editor::{TextEditor, VimState}; +use canvas::{DataProvider, AppMode}; use std::cell::RefCell; use std::rc::Rc; use tui_textarea::TextArea; @@ -277,174 +277,41 @@ impl Default for AddLogicState { } } -// Implement external library's CanvasState for AddLogicState -impl CanvasState for AddLogicState { - fn current_field(&self) -> usize { - match self.current_focus { - AddLogicFocus::InputLogicName => 0, - AddLogicFocus::InputTargetColumn => 1, - AddLogicFocus::InputDescription => 2, - // If focus is elsewhere, return the last canvas field used - _ => self.last_canvas_field, +impl DataProvider for AddLogicState { + fn field_count(&self) -> usize { + 3 // Logic Name, Target Column, Description + } + + fn field_name(&self, index: usize) -> &str { + match index { + 0 => "Logic Name", + 1 => "Target Column", + 2 => "Description", + _ => "", } } - fn set_current_field(&mut self, index: usize) { - let new_focus = match index { - 0 => AddLogicFocus::InputLogicName, - 1 => AddLogicFocus::InputTargetColumn, - 2 => AddLogicFocus::InputDescription, - _ => return, - }; - if self.current_focus != new_focus { - if self.current_focus == AddLogicFocus::InputTargetColumn { - self.in_target_column_suggestion_mode = false; - self.show_target_column_suggestions = false; - } - self.current_focus = new_focus; - self.last_canvas_field = index; + fn field_value(&self, index: usize) -> &str { + match index { + 0 => &self.logic_name_input, + 1 => &self.target_column_input, + 2 => &self.description_input, + _ => "", } } - fn current_cursor_pos(&self) -> usize { - match self.current_focus { - AddLogicFocus::InputLogicName => self.logic_name_cursor_pos, - AddLogicFocus::InputTargetColumn => self.target_column_cursor_pos, - AddLogicFocus::InputDescription => self.description_cursor_pos, - _ => 0, - } - } - - fn set_current_cursor_pos(&mut self, pos: usize) { - match self.current_focus { - AddLogicFocus::InputLogicName => { - self.logic_name_cursor_pos = pos.min(self.logic_name_input.len()); - } - AddLogicFocus::InputTargetColumn => { - self.target_column_cursor_pos = pos.min(self.target_column_input.len()); - } - AddLogicFocus::InputDescription => { - self.description_cursor_pos = pos.min(self.description_input.len()); - } + fn set_field_value(&mut self, index: usize, value: String) { + match index { + 0 => self.logic_name_input = value, + 1 => self.target_column_input = value, + 2 => self.description_input = value, _ => {} } + self.has_unsaved_changes = true; } - fn get_current_input(&self) -> &str { - match self.current_focus { - AddLogicFocus::InputLogicName => &self.logic_name_input, - AddLogicFocus::InputTargetColumn => &self.target_column_input, - AddLogicFocus::InputDescription => &self.description_input, - _ => "", // Should not happen if called correctly - } - } - - fn get_current_input_mut(&mut self) -> &mut String { - match self.current_focus { - AddLogicFocus::InputLogicName => &mut self.logic_name_input, - AddLogicFocus::InputTargetColumn => &mut self.target_column_input, - AddLogicFocus::InputDescription => &mut self.description_input, - _ => &mut self.logic_name_input, // Fallback - } - } - - fn inputs(&self) -> Vec<&String> { - vec![ - &self.logic_name_input, - &self.target_column_input, - &self.description_input, - ] - } - - fn fields(&self) -> Vec<&str> { - vec!["Logic Name", "Target Column", "Description"] - } - - fn has_unsaved_changes(&self) -> bool { - self.has_unsaved_changes - } - - fn set_has_unsaved_changes(&mut self, changed: bool) { - self.has_unsaved_changes = changed; - } - - fn handle_feature_action(&mut self, action: &CanvasAction, _context: &ActionContext) -> Option { - match action { - // Handle saving logic script - CanvasAction::Custom(action_str) if action_str == "save_logic" => { - self.save_logic() - } - - // Handle clearing the form - CanvasAction::Custom(action_str) if action_str == "clear_form" => { - self.clear_form() - } - - // Handle target column autocomplete activation - CanvasAction::Custom(action_str) if action_str == "activate_autocomplete" => { - if self.current_field() == 1 { // Target Column field - self.in_target_column_suggestion_mode = true; - self.update_target_column_suggestions(); - Some("Autocomplete activated".to_string()) - } else { - None - } - } - - // Handle target column suggestion selection - CanvasAction::Custom(action_str) if action_str == "select_suggestion" => { - if self.current_field() == 1 && self.in_target_column_suggestion_mode { - if let Some(selected_idx) = self.selected_target_column_suggestion_index { - if let Some(suggestion) = self.target_column_suggestions.get(selected_idx) { - self.target_column_input = suggestion.clone(); - self.target_column_cursor_pos = suggestion.len(); - self.in_target_column_suggestion_mode = false; - self.show_target_column_suggestions = false; - self.has_unsaved_changes = true; - return Some(format!("Selected: {}", suggestion)); - } - } - } - None - } - - // Custom validation when moving between fields - CanvasAction::NextField => { - match self.current_field() { - 0 => { // Logic Name field - if self.logic_name_input.trim().is_empty() { - Some("Logic name cannot be empty".to_string()) - } else { - None // Let canvas library handle the normal field movement - } - } - 1 => { // Target Column field - // Update suggestions when entering target column field - self.update_target_column_suggestions(); - None - } - _ => None, - } - } - - // Handle character insertion with validation - CanvasAction::InsertChar(c) => { - if self.current_field() == 1 { // Target Column field - // Update suggestions after character insertion - // Note: Canvas library will handle the actual insertion - // This is just for triggering suggestion updates - None // Let canvas handle insertion, then we'll update suggestions - } else { - None // Let canvas handle normally - } - } - - // Let canvas library handle everything else - _ => None, - } - } - - fn current_mode(&self) -> AppMode { - self.app_mode + fn supports_suggestions(&self, field_index: usize) -> bool { + // Only Target Column supports suggestions + field_index == 1 } } diff --git a/client/src/state/pages/add_table.rs b/client/src/state/pages/add_table.rs index 1e2a5e7..5531f49 100644 --- a/client/src/state/pages/add_table.rs +++ b/client/src/state/pages/add_table.rs @@ -170,3 +170,41 @@ impl AddTableState { } } } + +impl DataProvider for AddTableState { + fn field_count(&self) -> usize { + 3 // Table name, Column name, Column type + } + + fn field_name(&self, index: usize) -> &str { + match index { + 0 => "Table name", + 1 => "Name", + 2 => "Type", + _ => "", + } + } + + fn field_value(&self, index: usize) -> &str { + match index { + 0 => &self.table_name_input, + 1 => &self.column_name_input, + 2 => &self.column_type_input, + _ => "", + } + } + + fn set_field_value(&mut self, index: usize, value: String) { + match index { + 0 => self.table_name_input = value, + 1 => self.column_name_input = value, + 2 => self.column_type_input = value, + _ => {} + } + self.has_unsaved_changes = true; + } + + fn supports_suggestions(&self, _field_index: usize) -> bool { + false // AddTableState doesn’t use suggestions + } +}