From f4db0e384c7ea4072c6e667f7b53db5c06776e6a Mon Sep 17 00:00:00 2001 From: filipriec Date: Wed, 16 Apr 2025 22:23:30 +0200 Subject: [PATCH] add table page1 --- client/src/components/admin/add_table.rs | 205 +++++++++++++++++++++-- client/src/state/app/buffer.rs | 4 +- client/src/state/pages.rs | 1 + client/src/state/pages/add_table.rs | 68 ++++++++ client/src/state/pages/admin.rs | 2 + client/src/ui/handlers/render.rs | 9 + 6 files changed, 273 insertions(+), 16 deletions(-) create mode 100644 client/src/state/pages/add_table.rs diff --git a/client/src/components/admin/add_table.rs b/client/src/components/admin/add_table.rs index dd07a48..cc10715 100644 --- a/client/src/components/admin/add_table.rs +++ b/client/src/components/admin/add_table.rs @@ -1,32 +1,209 @@ // 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, Rect}, - style::{Style, Stylize}, - widgets::{Block, Borders, Paragraph}, + layout::{Alignment, Constraint, Direction, Layout, Rect}, + style::{Modifier, Style, Stylize}, + text::{Line, Span}, + widgets::{ + Block, BorderType, Borders, Cell, Paragraph, Row, Table, TableState, + }, Frame, }; -/// Renders a placeholder page for adding tables. -pub fn render_add_table_page( +/// Renders the detailed page for adding a new table. +pub fn render_add_table( f: &mut Frame, area: Rect, theme: &Theme, + app_state: &AppState, + add_table_state: &mut AddTableState, ) { - let block = Block::default() - .title(" Add New Table ") + let focused_style = Style::default().fg(theme.highlight); + let unfocused_style = Style::default().fg(theme.border); + let base_style = Style::default().fg(theme.fg); + let header_style = Style::default().fg(theme.secondary); + let selected_row_style = Style::default().bg(theme.highlight).fg(theme.bg); + + // --- Main Block --- + let main_block = Block::default() + .title(" Create New Table ") .borders(Borders::ALL) + .border_type(BorderType::Rounded) .border_style(Style::default().fg(theme.accent)) .style(Style::default().bg(theme.bg)); + let inner_area = main_block.inner(area); + f.render_widget(main_block, area); - let inner_area = block.inner(area); + // --- Layout --- + let constraints = [ + Constraint::Length(1), // Profile line + Constraint::Length(1), // Table Name line + Constraint::Length(1), // Spacer + Constraint::Length(1), // Columns Header + Constraint::Min(3), // Columns Table (at least 3 rows visible) + Constraint::Length(1), // Spacer + Constraint::Length(1), // Indexes Header + Constraint::Min(2), // Indexes Table + Constraint::Length(1), // Spacer + Constraint::Length(1), // Links Header + Constraint::Min(3), // Links Table + Constraint::Length(1), // Spacer + Constraint::Length(1), // Action Buttons + ]; + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints(constraints) + .margin(1) // Add margin inside the main block + .split(inner_area); - let text = Paragraph::new("This is the placeholder page for adding a new table.\n\nDrawing canvas coming soon!") - .style(Style::default().fg(theme.fg)) - .alignment(Alignment::Center); + // --- Helper: Get Border Style based on Focus --- + let get_border_style = |focus: AddTableFocus| { + if add_table_state.current_focus == focus { + focused_style + } else { + unfocused_style + } + }; - f.render_widget(block, area); - f.render_widget(text, inner_area); + // --- 1. Profile Line --- + // TODO: Fetch actual selected profile if needed, using app_state.selected_profile or admin_state + 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 --- + let table_name_block = Block::default() + .borders(Borders::BOTTOM) + .border_style(get_border_style(AddTableFocus::TableName)); + // Basic rendering for now, cursor needs event handling logic + 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 Header --- + let columns_header = Paragraph::new(Line::from(vec![ + Span::styled(" Name ", header_style), + Span::raw("| "), + Span::styled("Type ", header_style), + Span::raw("| "), + Span::styled(" <- Add Column (Ctrl+A)", header_style.add_modifier(Modifier::ITALIC)), + ])); + f.render_widget(columns_header, chunks[3]); + + // --- 5. Columns Table --- + let columns_block = Block::default() + .borders(Borders::TOP | Borders::BOTTOM) // Only top/bottom for visual separation + .border_style(get_border_style(AddTableFocus::Columns)); + let columns_table_area = columns_block.inner(chunks[4]); + f.render_widget(columns_block, chunks[4]); + + 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) + .highlight_style(selected_row_style) + .highlight_symbol("* "); // Indicate selection + f.render_stateful_widget( + columns_table, + columns_table_area, + &mut add_table_state.column_table_state, + ); + + // --- 7. Indexes Header --- + let indexes_header = Paragraph::new(Line::from(vec![ + Span::styled(" Column Name ", header_style), + Span::raw("| "), + Span::styled(" <- Add Index (Ctrl+I), Remove (Ctrl+X)", header_style.add_modifier(Modifier::ITALIC)), + ])); + f.render_widget(indexes_header, chunks[6]); + + // --- 8. Indexes Table --- + let indexes_block = Block::default() + .borders(Borders::TOP | Borders::BOTTOM) + .border_style(get_border_style(AddTableFocus::Indexes)); + let indexes_table_area = indexes_block.inner(chunks[7]); + f.render_widget(indexes_block, chunks[7]); + + 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) + .highlight_style(selected_row_style) + .highlight_symbol("* "); + f.render_stateful_widget( + indexes_table, + indexes_table_area, + &mut add_table_state.index_table_state, + ); + + // --- 10. Links Header --- + let links_header = Paragraph::new(Line::from(vec![ + Span::styled(" Linked Table ", header_style), + Span::raw("| "), + Span::styled("Required? ", header_style), + Span::raw("| "), + Span::styled(" <- Toggle Required (Space)", header_style.add_modifier(Modifier::ITALIC)), + ])); + f.render_widget(links_header, chunks[9]); + + // --- 11. Links Table --- + let links_block = Block::default() + .borders(Borders::TOP | Borders::BOTTOM) + .border_style(get_border_style(AddTableFocus::Links)); + let links_table_area = links_block.inner(chunks[10]); + f.render_widget(links_block, chunks[10]); + + let link_rows = add_table_state.links.iter().map(|link| { + let required_text = if link.is_required { "[X] Yes" } else { "[ ] No " }; // Pad No for alignment + 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) + .highlight_style(selected_row_style) + .highlight_symbol("* "); + f.render_stateful_widget( + links_table, + links_table_area, + &mut add_table_state.link_table_state, + ); + + // --- 13. Action Buttons --- + let button_layout = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Percentage(50), Constraint::Percentage(50)]) + .split(chunks[12]); + + let save_button = Paragraph::new("[ Save Table ]") + .alignment(Alignment::Center) + .style(if add_table_state.current_focus == AddTableFocus::SaveButton { + selected_row_style // Use selected style for focused button + } else { + base_style + }); + let cancel_button = Paragraph::new("[ Cancel ]") + .alignment(Alignment::Center) + .style(if add_table_state.current_focus == AddTableFocus::CancelButton { + selected_row_style + } else { + base_style + }); + + f.render_widget(save_button, button_layout[0]); + f.render_widget(cancel_button, button_layout[1]); } - diff --git a/client/src/state/app/buffer.rs b/client/src/state/app/buffer.rs index 137847b..83d24df 100644 --- a/client/src/state/app/buffer.rs +++ b/client/src/state/app/buffer.rs @@ -19,8 +19,8 @@ impl AppView { AppView::Intro => "Intro", AppView::Login => "Login", AppView::Register => "Register", - AppView::Admin => "Admin_panel", - AppView::AddTable => "Add_table", + AppView::Admin => "Admin_Panel", + AppView::AddTable => "Add_Table", AppView::Form(name) => name.as_str(), AppView::Scratch => "*scratch*", } diff --git a/client/src/state/pages.rs b/client/src/state/pages.rs index 1e02fd9..c22fb10 100644 --- a/client/src/state/pages.rs +++ b/client/src/state/pages.rs @@ -4,4 +4,5 @@ pub mod form; pub mod auth; pub mod admin; pub mod intro; +pub mod add_table; pub mod canvas_state; diff --git a/client/src/state/pages/add_table.rs b/client/src/state/pages/add_table.rs new file mode 100644 index 0000000..b1efc53 --- /dev/null +++ b/client/src/state/pages/add_table.rs @@ -0,0 +1,68 @@ +// src/state/pages/add_table.rs +use ratatui::widgets::TableState; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ColumnDefinition { + pub name: String, + pub data_type: String, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct LinkDefinition { + pub linked_table_name: String, + pub is_required: bool, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum AddTableFocus { + #[default] + TableName, + Columns, + Indexes, + Links, + SaveButton, + CancelButton, +} + +#[derive(Debug, Clone)] +pub struct AddTableState { + pub profile_name: String, + pub table_name: String, + pub columns: Vec, + pub indexes: Vec, + pub links: Vec, + pub current_focus: AddTableFocus, + pub column_table_state: TableState, + pub index_table_state: TableState, + pub link_table_state: TableState, + pub table_name_cursor_pos: usize, +} + +impl Default for AddTableState { + fn default() -> Self { + // Initialize with some dummy data for demonstration + AddTableState { + profile_name: "default".to_string(), // Should be set dynamically + table_name: "new_table".to_string(), + columns: vec![ + ColumnDefinition { name: "id".to_string(), data_type: "INTEGER".to_string() }, + ColumnDefinition { name: "name".to_string(), data_type: "TEXT".to_string() }, + ], + indexes: vec!["id".to_string()], + links: vec![ + LinkDefinition { linked_table_name: "related_table".to_string(), is_required: true }, + LinkDefinition { linked_table_name: "another_table".to_string(), is_required: false }, + ], + current_focus: AddTableFocus::TableName, + column_table_state: TableState::default().with_selected(0), + index_table_state: TableState::default().with_selected(0), + link_table_state: TableState::default().with_selected(0), + table_name_cursor_pos: 0, + } + } +} + +impl AddTableState { +} + + diff --git a/client/src/state/pages/admin.rs b/client/src/state/pages/admin.rs index 67f8fd1..b8a4093 100644 --- a/client/src/state/pages/admin.rs +++ b/client/src/state/pages/admin.rs @@ -1,6 +1,7 @@ // src/state/pages/admin.rs use ratatui::widgets::ListState; +use crate::state::pages::add_table::AddTableState; // Define the focus states for the admin panel panes #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] @@ -21,6 +22,7 @@ pub struct AdminState { pub selected_profile_index: Option, // Index with [*] in profiles (persistent) pub selected_table_index: Option, // Index with [*] in tables (persistent) pub current_focus: AdminFocus, // Tracks which pane is focused + pub add_table_state: AddTableState, } impl AdminState { diff --git a/client/src/ui/handlers/render.rs b/client/src/ui/handlers/render.rs index 874588e..67378d3 100644 --- a/client/src/ui/handlers/render.rs +++ b/client/src/ui/handlers/render.rs @@ -8,6 +8,7 @@ use crate::components::{ intro::intro::render_intro, handlers::sidebar::{self, calculate_sidebar_layout}, form::form::render_form, + admin::render_add_table, auth::{login::render_login, register::render_register}, }; use crate::config::colors::themes::Theme; @@ -96,6 +97,14 @@ pub fn render_ui( register_state.current_field < 4, highlight_state, ); + } else if app_state.ui.show_add_table { + render_add_table( + f, + main_content_area, + theme, + app_state, + &mut admin_state.add_table_state, + ); } else if app_state.ui.show_login { render_login( f,