from template to the working page

This commit is contained in:
filipriec
2025-04-17 11:11:33 +02:00
parent 8159a84447
commit f34317e504

View File

@@ -1,247 +1,192 @@
// 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, Constraint, Direction, Layout, Rect, Margin}, layout::{Alignment, Constraint, Direction, Layout, Rect},
style::{Modifier, Style, Stylize}, style::{Style, Stylize},
text::{Line, Span}, text::{Line, Span},
widgets::{ widgets::{Block, BorderType, Borders, Paragraph},
Block, BorderType, Borders, Cell, Paragraph, Row, Table, TableState,
},
Frame, 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( pub fn render_add_table(
f: &mut Frame, f: &mut Frame,
area: Rect, area: Rect,
theme: &Theme, theme: &Theme,
app_state: &AppState, // Read-only access needed app_state: &AppState,
add_table_state: &mut AddTableState, // Mutable for TableState add_table_state: &mut AddTableState,
) { ) {
let focused_style = Style::default().fg(theme.highlight); // Main block for the whole page
// 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 ---
let main_block = Block::default() let main_block = Block::default()
.title(" Create 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.accent)) .border_style(Style::default().fg(theme.border)) // Use theme border color
.style(Style::default().bg(theme.bg)); .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); f.render_widget(main_block, area);
// --- Layout (Single Vertical Column) --- // Split the inner area horizontally: Left info pane | Right input/action pane
let constraints = [ let horizontal_chunks = Layout::default()
Constraint::Length(1), // Profile line .direction(Direction::Horizontal)
Constraint::Length(1), // Table Name line (Input) .constraints([
Constraint::Length(1), // Spacer Constraint::Percentage(50), // Left Pane
Constraint::Length(1), // Columns Title Constraint::Percentage(50), // Right Pane
Constraint::Length(2), // Columns Canvas (Placeholder - Height 2) ].as_ref())
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(inner_area); .split(inner_area);
// --- Helper: Get Border Style based on Focus --- let left_pane = horizontal_chunks[0];
// Use this for elements that should show focus, like input placeholders or tables let right_pane = horizontal_chunks[1];
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
}
};
// --- 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 --- // Profile & Table Name section
let profile_text = format!("Profile: {}", add_table_state.profile_name); let profile_text = Paragraph::new(vec![
f.render_widget(Paragraph::new(profile_text).style(base_style), chunks[0]); Line::from(Span::styled("profile: default", theme.fg)), // Placeholder
Line::from(Span::styled("table name: [tablename]", theme.fg)), // Placeholder
// --- 2. Table Name Line (Input) --- ])
let table_name_block = Block::default() .block(
.borders(Borders::ALL) // Box around input Block::default()
.border_type(BorderType::Plain) .borders(Borders::BOTTOM)
.border_style(get_focus_border_style(AddTableFocus::TableName)); .border_style(Style::default().fg(theme.secondary)),
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,
); );
f.render_widget(profile_text, left_vertical_chunks[0]);
// --- 8. Indexes Title --- // Columns section
f.render_widget(Paragraph::new("Indexes").style(title_style), chunks[7]); 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) --- // Indexes section
let indexes_canvas_text = Paragraph::new("Column Name: [input]") let indexes_text = Paragraph::new(vec![
.style(get_placeholder_style(AddTableFocus::IndexInput)) Line::from(Span::styled("Column name", theme.accent)), // Header
.alignment(Alignment::Center); // Add index lines here later from state
f.render_widget(indexes_canvas_text, chunks[8]); ])
.block(
// --- 10. Indexes Results Table --- Block::default()
let indexes_table_block = Block::default() .title(Span::styled(" Indexes ", theme.fg))
.borders(Borders::TOP) .borders(Borders::TOP) // Separator from Columns
.border_style(get_focus_border_style(AddTableFocus::IndexesTable)); .border_style(Style::default().fg(theme.secondary)),
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,
); );
f.render_widget(indexes_text, left_vertical_chunks[3]);
// --- 12. Links Title --- // Links section
f.render_widget(Paragraph::new("Links (Dependencies)").style(title_style), chunks[11]); let links_text = Paragraph::new(vec![
Line::from(Span::styled("Linked table Required", theme.accent)), // Header
// --- 13. Links Canvas (Placeholder - No Border, Height 2) --- // Add link lines here later from state
let links_canvas_text = Paragraph::new("Linked Table: [input] | Required: [ ]") ])
.style(get_placeholder_style(AddTableFocus::LinkInput)) .block(
.alignment(Alignment::Center); Block::default()
f.render_widget(links_canvas_text, chunks[12]); .title(Span::styled(" Links ", theme.fg))
.borders(Borders::TOP) // Separator from Indexes
// --- 14. Links Results Table --- .border_style(Style::default().fg(theme.secondary)),
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,
); );
f.render_widget(links_text, left_vertical_chunks[5]);
// --- 16. Action Buttons --- // --- Right Pane ---
let button_layout = Layout::default() 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) .direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)]) .constraints([
.split(chunks[15]); // Use the last chunk index Constraint::Percentage(50), // Save Button
Constraint::Percentage(50), // Cancel Button
].as_ref())
.split(bottom_buttons_area);
// Style buttons similar to login page // Save Button (Placeholder)
let save_active = add_table_state.current_focus == AddTableFocus::SaveButton; let save_button = Paragraph::new(" Save table ")
let mut save_style = Style::default().fg(theme.fg); .style(Style::default().fg(theme.secondary)) // Default style
let mut save_border = Style::default().fg(theme.border); .alignment(Alignment::Center)
if save_active { .block(
save_style = save_style.fg(theme.highlight).add_modifier(Modifier::BOLD); Block::default()
save_border = save_border.fg(theme.accent); .borders(Borders::ALL)
} .border_type(BorderType::Rounded)
f.render_widget( .border_style(Style::default().fg(theme.secondary)), // Default style
Paragraph::new("Save Table") );
.style(save_style) f.render_widget(save_button, bottom_button_chunks[0]);
.alignment(Alignment::Center)
.block(
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Plain)
.border_style(save_border),
),
button_layout[0],
);
let cancel_active = add_table_state.current_focus == AddTableFocus::CancelButton; // Cancel Button (Placeholder)
let mut cancel_style = Style::default().fg(theme.fg); let cancel_button = Paragraph::new(" Cancel ")
let mut cancel_border = Style::default().fg(theme.border); .style(Style::default().fg(theme.secondary)) // Default style
if cancel_active { .alignment(Alignment::Center)
cancel_style = cancel_style.fg(theme.highlight).add_modifier(Modifier::BOLD); .block(
cancel_border = cancel_border.fg(theme.accent); Block::default()
} .borders(Borders::ALL)
f.render_widget( .border_type(BorderType::Rounded)
Paragraph::new("Cancel") .border_style(Style::default().fg(theme.secondary)), // Default style
.style(cancel_style) );
.alignment(Alignment::Center) f.render_widget(cancel_button, bottom_button_chunks[1]);
.block(
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Plain)
.border_style(cancel_border),
),
button_layout[1],
);
} }