diff --git a/client/src/components/admin/add_table.rs b/client/src/components/admin/add_table.rs index b4366c6..f0d7930 100644 --- a/client/src/components/admin/add_table.rs +++ b/client/src/components/admin/add_table.rs @@ -1,247 +1,192 @@ // src/components/admin/add_table.rs use crate::config::colors::themes::Theme; -use crate::state::{ - app::state::AppState, - pages::add_table::{AddTableFocus, AddTableState}, -}; use ratatui::{ - layout::{Alignment, Constraint, Direction, Layout, Rect, Margin}, - style::{Modifier, Style, Stylize}, + layout::{Alignment, Constraint, Direction, Layout, Rect}, + style::{Style, Stylize}, text::{Line, Span}, - widgets::{ - Block, BorderType, Borders, Cell, Paragraph, Row, Table, TableState, - }, + widgets::{Block, BorderType, Borders, Paragraph}, Frame, }; +use crate::state::app::state::AppState; +use crate::components::handlers::canvas::render_canvas; +use crate::state::pages::add_table::AddTableState; -/// Renders the detailed page for adding a new table with Title -> Canvas -> Results structure. +/// Renders a placeholder page for adding tables. pub fn render_add_table( f: &mut Frame, area: Rect, theme: &Theme, - app_state: &AppState, // Read-only access needed - add_table_state: &mut AddTableState, // Mutable for TableState + app_state: &AppState, + add_table_state: &mut AddTableState, ) { - let focused_style = Style::default().fg(theme.highlight); - // let unfocused_style = Style::default().fg(theme.border); // Keep if needed elsewhere - let base_style = Style::default().fg(theme.fg); - let title_style = Style::default().fg(theme.accent).add_modifier(Modifier::BOLD); - let selected_row_style = Style::default().bg(theme.highlight).fg(theme.bg); - let placeholder_style = Style::default().fg(theme.secondary).add_modifier(Modifier::ITALIC); - - // --- Main Block --- + // Main block for the whole page let main_block = Block::default() - .title(" Create New Table ") + .title(" Add New Table ") .borders(Borders::ALL) .border_type(BorderType::Rounded) - .border_style(Style::default().fg(theme.accent)) + .border_style(Style::default().fg(theme.border)) // Use theme border color .style(Style::default().bg(theme.bg)); - let inner_area = main_block.inner(area); // Area inside the main border + let inner_area = main_block.inner(area); f.render_widget(main_block, area); - // --- Layout (Single Vertical Column) --- - let constraints = [ - Constraint::Length(1), // Profile line - Constraint::Length(1), // Table Name line (Input) - Constraint::Length(1), // Spacer - Constraint::Length(1), // Columns Title - Constraint::Length(2), // Columns Canvas (Placeholder - Height 2) - Constraint::Min(3), // Columns Results Table - Constraint::Length(1), // Spacer - Constraint::Length(1), // Indexes Title - Constraint::Length(2), // Indexes Canvas (Placeholder - Height 2) - Constraint::Min(2), // Indexes Results Table - Constraint::Length(1), // Spacer - Constraint::Length(1), // Links Title - Constraint::Length(2), // Links Canvas (Placeholder - Height 2) - Constraint::Min(3), // Links Results Table - Constraint::Length(1), // Spacer - Constraint::Length(1), // Action Buttons - ]; - let chunks = Layout::default() - .direction(Direction::Vertical) - .constraints(constraints) - .margin(1) // Margin inside the main block + // Split the inner area horizontally: Left info pane | Right input/action pane + let horizontal_chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([ + Constraint::Percentage(50), // Left Pane + Constraint::Percentage(50), // Right Pane + ].as_ref()) .split(inner_area); - // --- Helper: Get Border Style based on Focus --- - // Use this for elements that should show focus, like input placeholders or tables - let get_focus_border_style = |focus_target: AddTableFocus| { - if add_table_state.current_focus == focus_target { - Style::default().fg(theme.highlight) - } else { - Style::default().fg(theme.border) // Keep border for tables/buttons - } - }; - // Helper for placeholder focus (no border, just text style change) - let get_placeholder_style = |focus_target: AddTableFocus| { - if add_table_state.current_focus == focus_target { - placeholder_style.fg(theme.highlight).remove_modifier(Modifier::ITALIC) - } else { - placeholder_style - } - }; + let left_pane = horizontal_chunks[0]; + let right_pane = horizontal_chunks[1]; + // --- Left Pane --- + let left_vertical_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(3), // Profile & Table Name header + Constraint::Min(5), // Columns section (expandable) + Constraint::Length(1), // Separator + Constraint::Min(3), // Indexes section (expandable) + Constraint::Length(1), // Separator + Constraint::Min(3), // Links section (expandable) + ].as_ref()) + .split(left_pane); - // --- 1. Profile Line --- - let profile_text = format!("Profile: {}", add_table_state.profile_name); - f.render_widget(Paragraph::new(profile_text).style(base_style), chunks[0]); - - // --- 2. Table Name Line (Input) --- - let table_name_block = Block::default() - .borders(Borders::ALL) // Box around input - .border_type(BorderType::Plain) - .border_style(get_focus_border_style(AddTableFocus::TableName)); - let table_name_text = format!("Table Name: [ {} ]", add_table_state.table_name); - let table_name_paragraph = Paragraph::new(table_name_text) - .style(base_style) - .block(table_name_block); - f.render_widget(table_name_paragraph, chunks[1]); - - // --- 4. Columns Title --- - f.render_widget(Paragraph::new("Columns").style(title_style), chunks[3]); - - // --- 5. Columns Canvas (Placeholder - No Border, Height 2) --- - let columns_canvas_text = Paragraph::new("Name: [input] | Type: [input]") - .style(get_placeholder_style(AddTableFocus::ColumnInput)) // Style text based on focus - .alignment(Alignment::Center); - f.render_widget(columns_canvas_text, chunks[4]); // Render directly into the chunk - - // --- 6. Columns Results Table --- - let columns_table_block = Block::default() - .borders(Borders::TOP) // Separator from canvas - .border_style(get_focus_border_style(AddTableFocus::ColumnsTable)); // Focus on table border - let columns_table_area = columns_table_block.inner(chunks[5]); - f.render_widget(columns_table_block, chunks[5]); - - let column_rows = add_table_state.columns.iter().map(|col| { - Row::new(vec![ - Cell::from(col.name.as_str()), - Cell::from(col.data_type.as_str()), - ]) - .style(base_style) - }); - let column_widths = [Constraint::Percentage(50), Constraint::Percentage(50)]; - let columns_table = Table::new(column_rows, column_widths) - .header(Row::new(vec!["Name", "Type"]).style(Style::default().fg(theme.secondary)).bottom_margin(1)) - .highlight_style(selected_row_style) - .highlight_symbol("* "); - f.render_stateful_widget( - columns_table, - columns_table_area, - &mut add_table_state.column_table_state, + // Profile & Table Name section + let profile_text = Paragraph::new(vec![ + Line::from(Span::styled("profile: default", theme.fg)), // Placeholder + Line::from(Span::styled("table name: [tablename]", theme.fg)), // Placeholder + ]) + .block( + Block::default() + .borders(Borders::BOTTOM) + .border_style(Style::default().fg(theme.secondary)), ); + f.render_widget(profile_text, left_vertical_chunks[0]); - // --- 8. Indexes Title --- - f.render_widget(Paragraph::new("Indexes").style(title_style), chunks[7]); + // Columns section + let columns_text = Paragraph::new(vec![ + 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))); + f.render_widget(columns_text, left_vertical_chunks[1]); - // --- 9. Indexes Canvas (Placeholder - No Border, Height 2) --- - let indexes_canvas_text = Paragraph::new("Column Name: [input]") - .style(get_placeholder_style(AddTableFocus::IndexInput)) - .alignment(Alignment::Center); - f.render_widget(indexes_canvas_text, chunks[8]); - - // --- 10. Indexes Results Table --- - let indexes_table_block = Block::default() - .borders(Borders::TOP) - .border_style(get_focus_border_style(AddTableFocus::IndexesTable)); - let indexes_table_area = indexes_table_block.inner(chunks[9]); - f.render_widget(indexes_table_block, chunks[9]); - - let index_rows = add_table_state.indexes.iter().map(|idx_col_name| { - Row::new(vec![Cell::from(idx_col_name.as_str())]).style(base_style) - }); - let index_widths = [Constraint::Percentage(100)]; - let indexes_table = Table::new(index_rows, index_widths) - .header(Row::new(vec!["Indexed Column"]).style(Style::default().fg(theme.secondary)).bottom_margin(1)) - .highlight_style(selected_row_style) - .highlight_symbol("* "); - f.render_stateful_widget( - indexes_table, - indexes_table_area, - &mut add_table_state.index_table_state, + // Indexes section + let indexes_text = Paragraph::new(vec![ + Line::from(Span::styled("Column name", theme.accent)), // Header + // Add index lines here later from state + ]) + .block( + Block::default() + .title(Span::styled(" Indexes ", theme.fg)) + .borders(Borders::TOP) // Separator from Columns + .border_style(Style::default().fg(theme.secondary)), ); + f.render_widget(indexes_text, left_vertical_chunks[3]); - // --- 12. Links Title --- - f.render_widget(Paragraph::new("Links (Dependencies)").style(title_style), chunks[11]); - - // --- 13. Links Canvas (Placeholder - No Border, Height 2) --- - let links_canvas_text = Paragraph::new("Linked Table: [input] | Required: [ ]") - .style(get_placeholder_style(AddTableFocus::LinkInput)) - .alignment(Alignment::Center); - f.render_widget(links_canvas_text, chunks[12]); - - // --- 14. Links Results Table --- - let links_table_block = Block::default() - .borders(Borders::TOP) - .border_style(get_focus_border_style(AddTableFocus::LinksTable)); - let links_table_area = links_table_block.inner(chunks[13]); - f.render_widget(links_table_block, chunks[13]); - - let link_rows = add_table_state.links.iter().map(|link| { - let required_text = if link.is_required { "[X] Yes" } else { "[ ] No " }; - Row::new(vec![ - Cell::from(link.linked_table_name.as_str()), - Cell::from(required_text), - ]) - .style(base_style) - }); - let link_widths = [Constraint::Percentage(70), Constraint::Percentage(30)]; - let links_table = Table::new(link_rows, link_widths) - .header(Row::new(vec!["Linked Table", "Required?"]).style(Style::default().fg(theme.secondary)).bottom_margin(1)) - .highlight_style(selected_row_style) - .highlight_symbol("* "); - f.render_stateful_widget( - links_table, - links_table_area, - &mut add_table_state.link_table_state, + // Links section + let links_text = Paragraph::new(vec![ + Line::from(Span::styled("Linked table Required", theme.accent)), // Header + // Add link lines here later from state + ]) + .block( + Block::default() + .title(Span::styled(" Links ", theme.fg)) + .borders(Borders::TOP) // Separator from Indexes + .border_style(Style::default().fg(theme.secondary)), ); + f.render_widget(links_text, left_vertical_chunks[5]); - // --- 16. Action Buttons --- - let button_layout = Layout::default() + // --- Right Pane --- + let right_vertical_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(7), // Input fields + Add button area + Constraint::Min(1), // Spacer + Constraint::Length(3), // Save/Cancel buttons area + ].as_ref()) + .split(right_pane); + + let input_area = right_vertical_chunks[0]; + let bottom_buttons_area = right_vertical_chunks[2]; + + // Input Area (Name, Type, Add Button) + let input_vertical_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(3), // Name Input + Constraint::Length(3), // Type Input + Constraint::Length(1), // Add Button + ].as_ref()) + .split(input_area); + + // Table Name Input (Placeholder) + let name_input_block = Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .title(" Table name ") + .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) + let add_button = Paragraph::new(" Add ") + .style(Style::default().fg(theme.secondary)) // Default style + .alignment(Alignment::Center) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .border_style(Style::default().fg(theme.secondary)), // Default style + ); + f.render_widget(add_button, input_vertical_chunks[2]); + + // Bottom Buttons Area (Save, Cancel) + let bottom_button_chunks = Layout::default() .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(50), Constraint::Percentage(50)]) - .split(chunks[15]); // Use the last chunk index + .constraints([ + Constraint::Percentage(50), // Save Button + Constraint::Percentage(50), // Cancel Button + ].as_ref()) + .split(bottom_buttons_area); - // Style buttons similar to login page - let save_active = add_table_state.current_focus == AddTableFocus::SaveButton; - let mut save_style = Style::default().fg(theme.fg); - let mut save_border = Style::default().fg(theme.border); - if save_active { - save_style = save_style.fg(theme.highlight).add_modifier(Modifier::BOLD); - save_border = save_border.fg(theme.accent); - } - f.render_widget( - Paragraph::new("Save Table") - .style(save_style) - .alignment(Alignment::Center) - .block( - Block::default() - .borders(Borders::ALL) - .border_type(BorderType::Plain) - .border_style(save_border), - ), - button_layout[0], - ); + // Save Button (Placeholder) + let save_button = Paragraph::new(" Save table ") + .style(Style::default().fg(theme.secondary)) // Default style + .alignment(Alignment::Center) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .border_style(Style::default().fg(theme.secondary)), // Default style + ); + f.render_widget(save_button, bottom_button_chunks[0]); - let cancel_active = add_table_state.current_focus == AddTableFocus::CancelButton; - let mut cancel_style = Style::default().fg(theme.fg); - let mut cancel_border = Style::default().fg(theme.border); - if cancel_active { - cancel_style = cancel_style.fg(theme.highlight).add_modifier(Modifier::BOLD); - cancel_border = cancel_border.fg(theme.accent); - } - f.render_widget( - Paragraph::new("Cancel") - .style(cancel_style) - .alignment(Alignment::Center) - .block( - Block::default() - .borders(Borders::ALL) - .border_type(BorderType::Plain) - .border_style(cancel_border), - ), - button_layout[1], - ); + // Cancel Button (Placeholder) + let cancel_button = Paragraph::new(" Cancel ") + .style(Style::default().fg(theme.secondary)) // Default style + .alignment(Alignment::Center) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .border_style(Style::default().fg(theme.secondary)), // Default style + ); + f.render_widget(cancel_button, bottom_button_chunks[1]); } -