needs improvements but at least it looks like it exists

This commit is contained in:
filipriec
2025-04-17 11:53:31 +02:00
parent f34317e504
commit 57f789290d
5 changed files with 323 additions and 140 deletions

View File

@@ -8,6 +8,8 @@ use ratatui::{
Frame, Frame,
}; };
use crate::state::app::state::AppState; use crate::state::app::state::AppState;
use crate::state::app::highlight::HighlightState;
use crate::state::pages::canvas_state::CanvasState;
use crate::components::handlers::canvas::render_canvas; use crate::components::handlers::canvas::render_canvas;
use crate::state::pages::add_table::AddTableState; use crate::state::pages::add_table::AddTableState;
@@ -16,15 +18,17 @@ pub fn render_add_table(
f: &mut Frame, f: &mut Frame,
area: Rect, area: Rect,
theme: &Theme, theme: &Theme,
app_state: &AppState, _app_state: &AppState,
add_table_state: &mut AddTableState, add_table_state: &mut AddTableState,
is_edit_mode: bool,
highlight_state: &HighlightState,
) { ) {
// Main block for the whole page // Main block for the whole page
let main_block = Block::default() let main_block = Block::default()
.title(" Add New Table ") .title(" Add New Table ")
.borders(Borders::ALL) .borders(Borders::ALL)
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.border_style(Style::default().fg(theme.border)) // Use theme border color .border_style(Style::default().fg(theme.border))
.style(Style::default().bg(theme.bg)); .style(Style::default().bg(theme.bg));
let inner_area = main_block.inner(area); let inner_area = main_block.inner(area);
f.render_widget(main_block, area); f.render_widget(main_block, area);
@@ -69,7 +73,6 @@ pub fn render_add_table(
// Columns section // Columns section
let columns_text = Paragraph::new(vec![ let columns_text = Paragraph::new(vec![
Line::from(Span::styled("Name Type", theme.accent)), // Header Line::from(Span::styled("Name Type", theme.accent)), // Header
// Add column lines here later from state
]) ])
.block(Block::default().title(Span::styled(" Columns ", theme.fg))); .block(Block::default().title(Span::styled(" Columns ", theme.fg)));
f.render_widget(columns_text, left_vertical_chunks[1]); f.render_widget(columns_text, left_vertical_chunks[1]);
@@ -77,7 +80,6 @@ pub fn render_add_table(
// Indexes section // Indexes section
let indexes_text = Paragraph::new(vec![ let indexes_text = Paragraph::new(vec![
Line::from(Span::styled("Column name", theme.accent)), // Header Line::from(Span::styled("Column name", theme.accent)), // Header
// Add index lines here later from state
]) ])
.block( .block(
Block::default() Block::default()
@@ -90,7 +92,6 @@ pub fn render_add_table(
// Links section // Links section
let links_text = Paragraph::new(vec![ let links_text = Paragraph::new(vec![
Line::from(Span::styled("Linked table Required", theme.accent)), // Header Line::from(Span::styled("Linked table Required", theme.accent)), // Header
// Add link lines here later from state
]) ])
.block( .block(
Block::default() Block::default()
@@ -104,58 +105,45 @@ pub fn render_add_table(
let right_vertical_chunks = Layout::default() let right_vertical_chunks = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.constraints([ .constraints([
Constraint::Length(7), // Input fields + Add button area Constraint::Length(5), // Area for render_canvas (3 fields + 2 border)
Constraint::Length(3), // Add Button Area
Constraint::Min(1), // Spacer Constraint::Min(1), // Spacer
Constraint::Length(3), // Save/Cancel buttons area Constraint::Length(3), // Save/Cancel buttons area
].as_ref()) ].as_ref())
.split(right_pane); .split(right_pane);
let input_area = right_vertical_chunks[0]; let canvas_area = right_vertical_chunks[0];
let bottom_buttons_area = right_vertical_chunks[2]; let add_button_area = right_vertical_chunks[1];
let bottom_buttons_area = right_vertical_chunks[3];
// Input Area (Name, Type, Add Button) // --- Use render_canvas for Inputs ---
let input_vertical_chunks = Layout::default() let _active_field_rect = render_canvas(
.direction(Direction::Vertical) f,
.constraints([ canvas_area,
Constraint::Length(3), // Name Input add_table_state,
Constraint::Length(3), // Type Input &[
Constraint::Length(1), // Add Button "Table name",
].as_ref()) "Name",
.split(input_area); "Type",
],
// Table Name Input (Placeholder) &add_table_state.current_field(),
let name_input_block = Block::default() &add_table_state.inputs().iter().map(|s| *s).collect::<Vec<&String>>(),
.borders(Borders::ALL) theme,
.border_type(BorderType::Rounded) is_edit_mode,
.title(" Table name ") highlight_state,
.border_style(Style::default().fg(theme.secondary)); // Default style );
let name_input_text = Paragraph::new("Name") // Placeholder text
.style(Style::default().fg(theme.fg))
.block(name_input_block);
f.render_widget(name_input_text, input_vertical_chunks[0]);
// Type Input (Placeholder)
let type_input_block = Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.title(" Type ")
.border_style(Style::default().fg(theme.secondary)); // Default style
let type_input_text = Paragraph::new("Type") // Placeholder text
.style(Style::default().fg(theme.fg))
.block(type_input_block);
f.render_widget(type_input_text, input_vertical_chunks[1]);
// Add Button (Placeholder) // Add Button (Placeholder)
let add_button = Paragraph::new(" Add ") let add_button = Paragraph::new(" Add ")
.style(Style::default().fg(theme.secondary)) // Default style .style(Style::default().fg(theme.secondary))
.alignment(Alignment::Center) .alignment(Alignment::Center)
.block( .block(
Block::default() Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.border_style(Style::default().fg(theme.secondary)), // Default style .border_style(Style::default().fg(theme.secondary)),
); );
f.render_widget(add_button, input_vertical_chunks[2]); f.render_widget(add_button, add_button_area);
// Bottom Buttons Area (Save, Cancel) // Bottom Buttons Area (Save, Cancel)
let bottom_button_chunks = Layout::default() let bottom_button_chunks = Layout::default()
@@ -168,25 +156,25 @@ pub fn render_add_table(
// Save Button (Placeholder) // Save Button (Placeholder)
let save_button = Paragraph::new(" Save table ") let save_button = Paragraph::new(" Save table ")
.style(Style::default().fg(theme.secondary)) // Default style .style(Style::default().fg(theme.secondary))
.alignment(Alignment::Center) .alignment(Alignment::Center)
.block( .block(
Block::default() Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.border_style(Style::default().fg(theme.secondary)), // Default style .border_style(Style::default().fg(theme.secondary)),
); );
f.render_widget(save_button, bottom_button_chunks[0]); f.render_widget(save_button, bottom_button_chunks[0]);
// Cancel Button (Placeholder) // Cancel Button (Placeholder)
let cancel_button = Paragraph::new(" Cancel ") let cancel_button = Paragraph::new(" Cancel ")
.style(Style::default().fg(theme.secondary)) // Default style .style(Style::default().fg(theme.secondary))
.alignment(Alignment::Center) .alignment(Alignment::Center)
.block( .block(
Block::default() Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.border_style(Style::default().fg(theme.secondary)), // Default style .border_style(Style::default().fg(theme.secondary)),
); );
f.render_widget(cancel_button, bottom_button_chunks[1]); f.render_widget(cancel_button, bottom_button_chunks[1]);
} }

View File

@@ -1,134 +1,222 @@
// src/functions/modes/navigation/add_table_nav.rs // src/functions/modes/navigation/add_table_nav.rs
use crate::state::pages::add_table::{AddTableFocus, AddTableState}; use crate::config::binds::config::Config;
use crate::state::app::state::AppState; // If needed for list lengths later use crate::state::{
app::state::AppState,
pages::add_table::{AddTableFocus, AddTableState},
};
use crossterm::event::{KeyEvent};
use ratatui::widgets::TableState; // Import TableState
/// Handles navigation events specifically for the Add Table page. /// Handles navigation events specifically for the Add Table view.
/// Returns true if the event was handled, false otherwise. /// Returns true if the event was handled, false otherwise.
pub fn handle_navigation( pub fn handle_add_table_navigation(
state: &mut AddTableState, key: KeyEvent,
action: &str, config: &Config,
// app_state: &AppState, // Add if needed for list lengths _app_state: &AppState, // Keep for potential future use (e.g., checking permissions)
add_table_state: &mut AddTableState,
command_message: &mut String,
) -> bool { ) -> bool {
let current_focus = state.current_focus; let action = config.get_general_action(key.code, key.modifiers);
let mut handled = true; // Assume handled unless proven otherwise let current_focus = add_table_state.current_focus;
let mut handled = true; // Assume handled unless logic determines otherwise
match action { match action.as_deref() {
"move_up" => { // --- Vertical Navigation (Up/Down) ---
state.current_focus = match current_focus { Some("move_up") => {
AddTableFocus::TableName => AddTableFocus::CancelButton, // Wrap around top let mut new_focus = current_focus; // Start with current focus
AddTableFocus::ColumnInput => AddTableFocus::TableName, match current_focus {
AddTableFocus::InputTableName => new_focus = AddTableFocus::CancelButton, // Wrap top
AddTableFocus::InputColumnName => new_focus = AddTableFocus::InputTableName,
AddTableFocus::InputColumnType => new_focus = AddTableFocus::InputColumnName,
AddTableFocus::AddColumnButton => new_focus = AddTableFocus::InputColumnType,
AddTableFocus::ColumnsTable => { AddTableFocus::ColumnsTable => {
// Navigate within table or move focus up if !navigate_table_up(&mut add_table_state.column_table_state, add_table_state.columns.len()) {
if !navigate_table_up(&mut state.column_table_state, state.columns.len()) { new_focus = AddTableFocus::AddColumnButton; // Move focus up if at table top
state.current_focus = AddTableFocus::ColumnInput;
} }
AddTableFocus::ColumnsTable // Keep focus here while navigating table // Keep focus on table while navigating within it
} }
AddTableFocus::IndexInput => AddTableFocus::ColumnsTable,
AddTableFocus::IndexesTable => { AddTableFocus::IndexesTable => {
if !navigate_table_up(&mut state.index_table_state, state.indexes.len()) { if !navigate_table_up(&mut add_table_state.index_table_state, add_table_state.indexes.len()) {
state.current_focus = AddTableFocus::IndexInput; new_focus = AddTableFocus::ColumnsTable; // Move focus up
} }
AddTableFocus::IndexesTable
} }
AddTableFocus::LinkInput => AddTableFocus::IndexesTable,
AddTableFocus::LinksTable => { AddTableFocus::LinksTable => {
if !navigate_table_up(&mut state.link_table_state, state.links.len()) { if !navigate_table_up(&mut add_table_state.link_table_state, add_table_state.links.len()) {
state.current_focus = AddTableFocus::LinkInput; new_focus = AddTableFocus::IndexesTable; // Move focus up
} }
AddTableFocus::LinksTable
} }
AddTableFocus::SaveButton | AddTableFocus::CancelButton => AddTableFocus::LinksTable, AddTableFocus::SaveButton => new_focus = AddTableFocus::LinksTable,
AddTableFocus::CancelButton => new_focus = AddTableFocus::SaveButton,
} }
add_table_state.current_focus = new_focus;
*command_message = format!("Focus set to {:?}", add_table_state.current_focus);
} }
"move_down" => { Some("move_down") => {
state.current_focus = match current_focus { let mut new_focus = current_focus; // Start with current focus
AddTableFocus::TableName => AddTableFocus::ColumnInput, match current_focus {
AddTableFocus::ColumnInput => AddTableFocus::ColumnsTable, AddTableFocus::InputTableName => new_focus = AddTableFocus::InputColumnName,
AddTableFocus::InputColumnName => new_focus = AddTableFocus::InputColumnType,
AddTableFocus::InputColumnType => new_focus = AddTableFocus::AddColumnButton,
AddTableFocus::AddColumnButton => new_focus = AddTableFocus::ColumnsTable,
AddTableFocus::ColumnsTable => { AddTableFocus::ColumnsTable => {
if !navigate_table_down(&mut state.column_table_state, state.columns.len()) { if !navigate_table_down(&mut add_table_state.column_table_state, add_table_state.columns.len()) {
state.current_focus = AddTableFocus::IndexInput; new_focus = AddTableFocus::IndexesTable; // Move focus down if at table bottom
} }
AddTableFocus::ColumnsTable // Keep focus on table while navigating within it
} }
AddTableFocus::IndexInput => AddTableFocus::IndexesTable,
AddTableFocus::IndexesTable => { AddTableFocus::IndexesTable => {
if !navigate_table_down(&mut state.index_table_state, state.indexes.len()) { if !navigate_table_down(&mut add_table_state.index_table_state, add_table_state.indexes.len()) {
state.current_focus = AddTableFocus::LinkInput; new_focus = AddTableFocus::LinksTable; // Move focus down
} }
AddTableFocus::IndexesTable
} }
AddTableFocus::LinkInput => AddTableFocus::LinksTable,
AddTableFocus::LinksTable => { AddTableFocus::LinksTable => {
if !navigate_table_down(&mut state.link_table_state, state.links.len()) { if !navigate_table_down(&mut add_table_state.link_table_state, add_table_state.links.len()) {
// Move to buttons after table new_focus = AddTableFocus::SaveButton; // Move focus down
state.current_focus = AddTableFocus::SaveButton;
} }
AddTableFocus::LinksTable
} }
AddTableFocus::SaveButton | AddTableFocus::CancelButton => AddTableFocus::TableName, // Wrap around bottom AddTableFocus::SaveButton => new_focus = AddTableFocus::CancelButton,
AddTableFocus::CancelButton => new_focus = AddTableFocus::InputTableName, // Wrap bottom
} }
add_table_state.current_focus = new_focus;
*command_message = format!("Focus set to {:?}", add_table_state.current_focus);
} }
"next_option" => { // Typically Tab or Right arrow
state.current_focus = match current_focus { // --- Horizontal Navigation (Left/Right) ---
// Simple vertical flow for now, like move_down Some("next_option") => { // 'l' or Right
AddTableFocus::TableName => AddTableFocus::ColumnInput, add_table_state.current_focus = match current_focus {
AddTableFocus::ColumnInput => AddTableFocus::ColumnsTable, AddTableFocus::SaveButton => AddTableFocus::CancelButton,
AddTableFocus::ColumnsTable => AddTableFocus::IndexInput, _ => current_focus, // No change for others yet
AddTableFocus::IndexInput => AddTableFocus::IndexesTable, };
AddTableFocus::IndexesTable => AddTableFocus::LinkInput, *command_message = format!("Focus set to {:?}", add_table_state.current_focus);
AddTableFocus::LinkInput => AddTableFocus::LinksTable, }
Some("previous_option") => { // 'h' or Left
add_table_state.current_focus = match current_focus {
AddTableFocus::CancelButton => AddTableFocus::SaveButton,
_ => current_focus, // No change for others yet
};
*command_message = format!("Focus set to {:?}", add_table_state.current_focus);
}
// --- Tab / Shift+Tab Navigation ---
Some("next_field") => { // Tab
add_table_state.current_focus = match current_focus {
AddTableFocus::InputTableName => AddTableFocus::InputColumnName,
AddTableFocus::InputColumnName => AddTableFocus::InputColumnType,
AddTableFocus::InputColumnType => AddTableFocus::AddColumnButton,
AddTableFocus::AddColumnButton => AddTableFocus::ColumnsTable,
AddTableFocus::ColumnsTable => AddTableFocus::IndexesTable,
AddTableFocus::IndexesTable => AddTableFocus::LinksTable,
AddTableFocus::LinksTable => AddTableFocus::SaveButton, AddTableFocus::LinksTable => AddTableFocus::SaveButton,
AddTableFocus::SaveButton => AddTableFocus::CancelButton, AddTableFocus::SaveButton => AddTableFocus::CancelButton,
AddTableFocus::CancelButton => AddTableFocus::TableName, // Wrap AddTableFocus::CancelButton => AddTableFocus::InputTableName, // Wrap
} };
*command_message = format!("Focus set to {:?}", add_table_state.current_focus);
} }
"previous_option" => { // Typically Shift+Tab or Left arrow Some("prev_field") => { // Shift+Tab
state.current_focus = match current_focus { add_table_state.current_focus = match current_focus {
// Simple vertical flow upwards AddTableFocus::InputTableName => AddTableFocus::CancelButton, // Wrap
AddTableFocus::TableName => AddTableFocus::CancelButton, // Wrap AddTableFocus::InputColumnName => AddTableFocus::InputTableName,
AddTableFocus::ColumnInput => AddTableFocus::TableName, AddTableFocus::InputColumnType => AddTableFocus::InputColumnName,
AddTableFocus::ColumnsTable => AddTableFocus::ColumnInput, AddTableFocus::AddColumnButton => AddTableFocus::InputColumnType,
AddTableFocus::IndexInput => AddTableFocus::ColumnsTable, AddTableFocus::ColumnsTable => AddTableFocus::AddColumnButton,
AddTableFocus::IndexesTable => AddTableFocus::IndexInput, AddTableFocus::IndexesTable => AddTableFocus::ColumnsTable,
AddTableFocus::LinkInput => AddTableFocus::IndexesTable, AddTableFocus::LinksTable => AddTableFocus::IndexesTable,
AddTableFocus::LinksTable => AddTableFocus::LinkInput,
AddTableFocus::SaveButton => AddTableFocus::LinksTable, AddTableFocus::SaveButton => AddTableFocus::LinksTable,
AddTableFocus::CancelButton => AddTableFocus::SaveButton, AddTableFocus::CancelButton => AddTableFocus::SaveButton,
};
*command_message = format!("Focus set to {:?}", add_table_state.current_focus);
}
// --- Selection ---
Some("select") => {
match current_focus {
AddTableFocus::AddColumnButton => {
*command_message = "Action: Add Column (Not Implemented)".to_string();
// TODO: Implement logic to add column based on inputs
// Clear input fields, add to columns list, mark unsaved changes
// add_table_state.add_column(); // Example method call
}
AddTableFocus::SaveButton => {
*command_message = "Action: Save Table (Not Implemented)".to_string();
// TODO: Implement logic to save table (e.g., call API)
// Mark changes as saved
// add_table_state.save_table(); // Example method call
}
AddTableFocus::CancelButton => {
*command_message = "Action: Cancel Add Table".to_string();
// TODO: Implement logic to navigate back (e.g., update AppView history)
// Maybe show a confirmation dialog if there are unsaved changes
// buffer_state.go_back(); // Example call
}
// Selecting input fields usually means entering Edit mode (handled elsewhere)
// Selecting tables might mean focusing on them for editing/deletion (TODO)
AddTableFocus::ColumnsTable => {
if let Some(index) = add_table_state.column_table_state.selected() {
*command_message = format!("Selected column index {}", index);
// TODO: Add logic for editing/deleting selected column
} else {
*command_message = "No column selected".to_string();
}
}
AddTableFocus::IndexesTable => {
if let Some(index) = add_table_state.index_table_state.selected() {
*command_message = format!("Selected index index {}", index);
// TODO: Add logic for editing/deleting selected index
} else {
*command_message = "No index selected".to_string();
}
}
AddTableFocus::LinksTable => {
if let Some(index) = add_table_state.link_table_state.selected() {
*command_message = format!("Selected link index {}", index);
// TODO: Add logic for editing/deleting selected link
} else {
*command_message = "No link selected".to_string();
}
}
_ => {
// For InputTableName, InputColumnName, InputColumnType,
// the main event loop should handle 'select' by potentially
// switching to Edit mode if not already in it.
// We don't need specific logic here for that.
*command_message = format!("Select on {:?}", current_focus);
handled = false; // Let main loop handle edit mode toggle maybe
}
} }
} }
"select" => {
// TODO: Implement select action based on current_focus // --- Other General Keys (Ignore for add_table nav) ---
// e.g., Enter edit mode for TableName/Inputs, toggle link required, trigger save/cancel Some("toggle_sidebar") | Some("toggle_buffer_list") => {
handled = false; // Mark as not handled for now handled = false; // Let global handler manage these
} }
_ => handled = false, // Action not relevant for this navigation
// --- No matching action ---
_ => handled = false, // Event not handled by add_table navigation
} }
// If focus changed to a table, select the first row if nothing is selected // If focus changed TO a table, select the first row if nothing is selected
if handled && current_focus != state.current_focus { if handled && current_focus != add_table_state.current_focus {
match state.current_focus { match add_table_state.current_focus {
AddTableFocus::ColumnsTable if state.column_table_state.selected().is_none() && !state.columns.is_empty() => { AddTableFocus::ColumnsTable if add_table_state.column_table_state.selected().is_none() && !add_table_state.columns.is_empty() => {
state.column_table_state.select(Some(0)); add_table_state.column_table_state.select(Some(0));
} }
AddTableFocus::IndexesTable if state.index_table_state.selected().is_none() && !state.indexes.is_empty() => { AddTableFocus::IndexesTable if add_table_state.index_table_state.selected().is_none() && !add_table_state.indexes.is_empty() => {
state.index_table_state.select(Some(0)); add_table_state.index_table_state.select(Some(0));
} }
AddTableFocus::LinksTable if state.link_table_state.selected().is_none() && !state.links.is_empty() => { AddTableFocus::LinksTable if add_table_state.link_table_state.selected().is_none() && !add_table_state.links.is_empty() => {
state.link_table_state.select(Some(0)); add_table_state.link_table_state.select(Some(0));
} }
_ => {} // No action needed for other focus states _ => {} // No action needed for other focus states
} }
} }
handled handled
} }
// Helper function for navigating up within a table state // Helper function for navigating up within a table state
// Returns true if navigation happened within the table, false if it reached the top // Returns true if navigation happened within the table, false if it reached the top
fn navigate_table_up(table_state: &mut ratatui::widgets::TableState, item_count: usize) -> bool { fn navigate_table_up(table_state: &mut TableState, item_count: usize) -> bool {
if item_count == 0 { return false; } // Cannot navigate empty table if item_count == 0 { return false; } // Cannot navigate empty table
let current_selection = table_state.selected(); let current_selection = table_state.selected();
match current_selection { match current_selection {
@@ -141,7 +229,8 @@ fn navigate_table_up(table_state: &mut ratatui::widgets::TableState, item_count:
} }
} }
None => { None => {
table_state.select(Some(item_count - 1)); // Select last item if nothing selected // If nothing selected, moving up could select the last item
table_state.select(Some(item_count - 1));
true true
} }
} }
@@ -149,7 +238,7 @@ fn navigate_table_up(table_state: &mut ratatui::widgets::TableState, item_count:
// Helper function for navigating down within a table state // Helper function for navigating down within a table state
// Returns true if navigation happened within the table, false if it reached the bottom // Returns true if navigation happened within the table, false if it reached the bottom
fn navigate_table_down(table_state: &mut ratatui::widgets::TableState, item_count: usize) -> bool { fn navigate_table_down(table_state: &mut TableState, item_count: usize) -> bool {
if item_count == 0 { return false; } // Cannot navigate empty table if item_count == 0 { return false; } // Cannot navigate empty table
let current_selection = table_state.selected(); let current_selection = table_state.selected();
match current_selection { match current_selection {
@@ -162,8 +251,10 @@ fn navigate_table_down(table_state: &mut ratatui::widgets::TableState, item_coun
} }
} }
None => { None => {
table_state.select(Some(0)); // Select first item if nothing selected // If nothing selected, moving down could select the first item
table_state.select(Some(0));
true true
} }
} }
} }

View File

@@ -178,11 +178,15 @@ impl EventHandler {
// --- Add Table Page Navigation --- // --- Add Table Page Navigation ---
if app_state.ui.show_add_table { if app_state.ui.show_add_table {
if let Some(action) = config.get_general_action(key.code, key.modifiers) { if let Some(action) = config.get_general_action(key.code, key.modifiers) {
if add_table_nav::handle_navigation( if add_table_nav::handle_add_table_navigation(
key,
config,
app_state,
&mut admin_state.add_table_state, &mut admin_state.add_table_state,
action, &mut self.command_message,
) { ) {
return Ok(EventOutcome::Ok(String::new())); return Ok(EventOutcome::Ok(self.command_message.clone()));
} }
} }
} }

View File

@@ -1,4 +1,5 @@
// src/state/pages/add_table.rs // src/state/pages/add_table.rs
use crate::state::pages::canvas_state::CanvasState;
use ratatui::widgets::TableState; use ratatui::widgets::TableState;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@@ -16,11 +17,10 @@ pub struct LinkDefinition {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum AddTableFocus { pub enum AddTableFocus {
#[default] #[default]
TableName, InputTableName, // Field 0 for CanvasState
// Input areas (placeholders for now) InputColumnName, // Field 1 for CanvasState
ColumnInput, InputColumnType, // Field 2 for CanvasState
IndexInput, AddColumnButton,
LinkInput,
// Result Tables // Result Tables
ColumnsTable, ColumnsTable,
IndexesTable, IndexesTable,
@@ -34,6 +34,8 @@ pub enum AddTableFocus {
pub struct AddTableState { pub struct AddTableState {
pub profile_name: String, pub profile_name: String,
pub table_name: String, pub table_name: String,
pub column_name_input: String,
pub column_type_input: String,
pub columns: Vec<ColumnDefinition>, pub columns: Vec<ColumnDefinition>,
pub indexes: Vec<String>, pub indexes: Vec<String>,
pub links: Vec<LinkDefinition>, pub links: Vec<LinkDefinition>,
@@ -42,6 +44,9 @@ pub struct AddTableState {
pub index_table_state: TableState, pub index_table_state: TableState,
pub link_table_state: TableState, pub link_table_state: TableState,
pub table_name_cursor_pos: usize, pub table_name_cursor_pos: usize,
pub column_name_cursor_pos: usize,
pub column_type_cursor_pos: usize,
pub has_unsaved_changes: bool,
} }
impl Default for AddTableState { impl Default for AddTableState {
@@ -49,7 +54,9 @@ impl Default for AddTableState {
// Initialize with some dummy data for demonstration // Initialize with some dummy data for demonstration
AddTableState { AddTableState {
profile_name: "default".to_string(), // Should be set dynamically profile_name: "default".to_string(), // Should be set dynamically
table_name: "new_table".to_string(), table_name: String::new(), // Start empty
column_name_input: String::new(),
column_type_input: String::new(),
columns: vec![ columns: vec![
ColumnDefinition { name: "id".to_string(), data_type: "INTEGER".to_string() }, ColumnDefinition { name: "id".to_string(), data_type: "INTEGER".to_string() },
ColumnDefinition { name: "name".to_string(), data_type: "TEXT".to_string() }, ColumnDefinition { name: "name".to_string(), data_type: "TEXT".to_string() },
@@ -59,16 +66,107 @@ impl Default for AddTableState {
LinkDefinition { linked_table_name: "related_table".to_string(), is_required: true }, LinkDefinition { linked_table_name: "related_table".to_string(), is_required: true },
LinkDefinition { linked_table_name: "another_table".to_string(), is_required: false }, LinkDefinition { linked_table_name: "another_table".to_string(), is_required: false },
], ],
current_focus: AddTableFocus::TableName, current_focus: AddTableFocus::InputTableName,
column_table_state: TableState::default().with_selected(0), column_table_state: TableState::default().with_selected(0),
index_table_state: TableState::default().with_selected(0), index_table_state: TableState::default().with_selected(0),
link_table_state: TableState::default().with_selected(0), link_table_state: TableState::default().with_selected(0),
table_name_cursor_pos: 0, table_name_cursor_pos: 0,
column_name_cursor_pos: 0,
column_type_cursor_pos: 0,
has_unsaved_changes: false,
} }
} }
} }
impl AddTableState { impl AddTableState {
const INPUT_FIELD_COUNT: usize = 3;
} }
// Implement CanvasState for the input fields
impl CanvasState for AddTableState {
fn current_field(&self) -> usize {
match self.current_focus {
AddTableFocus::InputTableName => 0,
AddTableFocus::InputColumnName => 1,
AddTableFocus::InputColumnType => 2,
// If focus is elsewhere, default to the first field for canvas rendering logic
_ => 0,
}
}
fn current_cursor_pos(&self) -> usize {
match self.current_focus {
AddTableFocus::InputTableName => self.table_name_cursor_pos,
AddTableFocus::InputColumnName => self.column_name_cursor_pos,
AddTableFocus::InputColumnType => self.column_type_cursor_pos,
_ => 0, // Default if focus is not on an input field
}
}
fn has_unsaved_changes(&self) -> bool {
self.has_unsaved_changes
}
fn inputs(&self) -> Vec<&String> {
vec![&self.table_name, &self.column_name_input, &self.column_type_input]
}
fn get_current_input(&self) -> &str {
match self.current_focus {
AddTableFocus::InputTableName => &self.table_name,
AddTableFocus::InputColumnName => &self.column_name_input,
AddTableFocus::InputColumnType => &self.column_type_input,
_ => "", // Should not happen if called correctly
}
}
fn get_current_input_mut(&mut self) -> &mut String {
match self.current_focus {
AddTableFocus::InputTableName => &mut self.table_name,
AddTableFocus::InputColumnName => &mut self.column_name_input,
AddTableFocus::InputColumnType => &mut self.column_type_input,
// This case needs careful handling. If focus isn't on an input,
// which mutable string should we return? Returning the first one
// might be unexpected. Consider panicking or returning Option if this state is invalid.
// For now, returning the first field to avoid panics during rendering.
_ => &mut self.table_name,
}
}
fn fields(&self) -> Vec<&str> {
// These must match the order used in render_add_table
vec!["Table name", "Name", "Type"]
}
fn set_current_field(&mut self, index: usize) {
self.current_focus = match index {
0 => AddTableFocus::InputTableName,
1 => AddTableFocus::InputColumnName,
2 => AddTableFocus::InputColumnType,
_ => self.current_focus, // Stay on current focus if index is out of bounds
};
}
fn set_current_cursor_pos(&mut self, pos: usize) {
match self.current_focus {
AddTableFocus::InputTableName => self.table_name_cursor_pos = pos,
AddTableFocus::InputColumnName => self.column_name_cursor_pos = pos,
AddTableFocus::InputColumnType => self.column_type_cursor_pos = pos,
_ => {} // Do nothing if focus is not on an input field
}
}
fn set_has_unsaved_changes(&mut self, changed: bool) {
self.has_unsaved_changes = changed;
}
// --- Autocomplete Support (Not needed for this form yet) ---
fn get_suggestions(&self) -> Option<&[String]> {
None
}
fn get_selected_suggestion_index(&self) -> Option<usize> {
None
}
}

View File

@@ -104,6 +104,8 @@ pub fn render_ui(
theme, theme,
app_state, app_state,
&mut admin_state.add_table_state, &mut admin_state.add_table_state,
login_state.current_field < 3,
highlight_state,
); );
} else if app_state.ui.show_login { } else if app_state.ui.show_login {
render_login( render_login(