add table page1
This commit is contained in:
@@ -1,32 +1,209 @@
|
|||||||
// src/components/admin/add_table.rs
|
// src/components/admin/add_table.rs
|
||||||
use crate::config::colors::themes::Theme;
|
use crate::config::colors::themes::Theme;
|
||||||
|
use crate::state::{
|
||||||
|
app::state::AppState,
|
||||||
|
pages::add_table::{AddTableFocus, AddTableState},
|
||||||
|
};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Alignment, Rect},
|
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
||||||
style::{Style, Stylize},
|
style::{Modifier, Style, Stylize},
|
||||||
widgets::{Block, Borders, Paragraph},
|
text::{Line, Span},
|
||||||
|
widgets::{
|
||||||
|
Block, BorderType, Borders, Cell, Paragraph, Row, Table, TableState,
|
||||||
|
},
|
||||||
Frame,
|
Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Renders a placeholder page for adding tables.
|
/// Renders the detailed page for adding a new table.
|
||||||
pub fn render_add_table_page(
|
pub fn render_add_table(
|
||||||
f: &mut Frame,
|
f: &mut Frame,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
|
app_state: &AppState,
|
||||||
|
add_table_state: &mut AddTableState,
|
||||||
) {
|
) {
|
||||||
let block = Block::default()
|
let focused_style = Style::default().fg(theme.highlight);
|
||||||
.title(" Add New Table ")
|
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)
|
.borders(Borders::ALL)
|
||||||
|
.border_type(BorderType::Rounded)
|
||||||
.border_style(Style::default().fg(theme.accent))
|
.border_style(Style::default().fg(theme.accent))
|
||||||
.style(Style::default().bg(theme.bg));
|
.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!")
|
// --- Helper: Get Border Style based on Focus ---
|
||||||
.style(Style::default().fg(theme.fg))
|
let get_border_style = |focus: AddTableFocus| {
|
||||||
.alignment(Alignment::Center);
|
if add_table_state.current_focus == focus {
|
||||||
|
focused_style
|
||||||
|
} else {
|
||||||
|
unfocused_style
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
f.render_widget(block, area);
|
// --- 1. Profile Line ---
|
||||||
f.render_widget(text, inner_area);
|
// 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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ impl AppView {
|
|||||||
AppView::Intro => "Intro",
|
AppView::Intro => "Intro",
|
||||||
AppView::Login => "Login",
|
AppView::Login => "Login",
|
||||||
AppView::Register => "Register",
|
AppView::Register => "Register",
|
||||||
AppView::Admin => "Admin_panel",
|
AppView::Admin => "Admin_Panel",
|
||||||
AppView::AddTable => "Add_table",
|
AppView::AddTable => "Add_Table",
|
||||||
AppView::Form(name) => name.as_str(),
|
AppView::Form(name) => name.as_str(),
|
||||||
AppView::Scratch => "*scratch*",
|
AppView::Scratch => "*scratch*",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ pub mod form;
|
|||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod admin;
|
pub mod admin;
|
||||||
pub mod intro;
|
pub mod intro;
|
||||||
|
pub mod add_table;
|
||||||
pub mod canvas_state;
|
pub mod canvas_state;
|
||||||
|
|||||||
68
client/src/state/pages/add_table.rs
Normal file
68
client/src/state/pages/add_table.rs
Normal file
@@ -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<ColumnDefinition>,
|
||||||
|
pub indexes: Vec<String>,
|
||||||
|
pub links: Vec<LinkDefinition>,
|
||||||
|
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 {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/state/pages/admin.rs
|
// src/state/pages/admin.rs
|
||||||
|
|
||||||
use ratatui::widgets::ListState;
|
use ratatui::widgets::ListState;
|
||||||
|
use crate::state::pages::add_table::AddTableState;
|
||||||
|
|
||||||
// Define the focus states for the admin panel panes
|
// Define the focus states for the admin panel panes
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
@@ -21,6 +22,7 @@ pub struct AdminState {
|
|||||||
pub selected_profile_index: Option<usize>, // Index with [*] in profiles (persistent)
|
pub selected_profile_index: Option<usize>, // Index with [*] in profiles (persistent)
|
||||||
pub selected_table_index: Option<usize>, // Index with [*] in tables (persistent)
|
pub selected_table_index: Option<usize>, // Index with [*] in tables (persistent)
|
||||||
pub current_focus: AdminFocus, // Tracks which pane is focused
|
pub current_focus: AdminFocus, // Tracks which pane is focused
|
||||||
|
pub add_table_state: AddTableState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AdminState {
|
impl AdminState {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use crate::components::{
|
|||||||
intro::intro::render_intro,
|
intro::intro::render_intro,
|
||||||
handlers::sidebar::{self, calculate_sidebar_layout},
|
handlers::sidebar::{self, calculate_sidebar_layout},
|
||||||
form::form::render_form,
|
form::form::render_form,
|
||||||
|
admin::render_add_table,
|
||||||
auth::{login::render_login, register::render_register},
|
auth::{login::render_login, register::render_register},
|
||||||
};
|
};
|
||||||
use crate::config::colors::themes::Theme;
|
use crate::config::colors::themes::Theme;
|
||||||
@@ -96,6 +97,14 @@ pub fn render_ui(
|
|||||||
register_state.current_field < 4,
|
register_state.current_field < 4,
|
||||||
highlight_state,
|
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 {
|
} else if app_state.ui.show_login {
|
||||||
render_login(
|
render_login(
|
||||||
f,
|
f,
|
||||||
|
|||||||
Reference in New Issue
Block a user