This commit is contained in:
filipriec
2025-04-16 23:31:28 +02:00
parent f4db0e384c
commit 8159a84447
6 changed files with 318 additions and 93 deletions

View File

@@ -5,7 +5,7 @@ use crate::state::{
pages::add_table::{AddTableFocus, AddTableState},
};
use ratatui::{
layout::{Alignment, Constraint, Direction, Layout, Rect},
layout::{Alignment, Constraint, Direction, Layout, Rect, Margin},
style::{Modifier, Style, Stylize},
text::{Line, Span},
widgets::{
@@ -14,19 +14,20 @@ use ratatui::{
Frame,
};
/// Renders the detailed page for adding a new table.
/// Renders the detailed page for adding a new table with Title -> Canvas -> Results structure.
pub fn render_add_table(
f: &mut Frame,
area: Rect,
theme: &Theme,
app_state: &AppState,
add_table_state: &mut AddTableState,
app_state: &AppState, // Read-only access needed
add_table_state: &mut AddTableState, // Mutable for TableState
) {
let focused_style = Style::default().fg(theme.highlight);
let unfocused_style = Style::default().fg(theme.border);
// let unfocused_style = Style::default().fg(theme.border); // Keep if needed elsewhere
let base_style = Style::default().fg(theme.fg);
let header_style = Style::default().fg(theme.secondary);
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()
@@ -35,72 +36,83 @@ pub fn render_add_table(
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(theme.accent))
.style(Style::default().bg(theme.bg));
let inner_area = main_block.inner(area);
let inner_area = main_block.inner(area); // Area inside the main border
f.render_widget(main_block, area);
// --- Layout ---
// --- Layout (Single Vertical Column) ---
let constraints = [
Constraint::Length(1), // Profile line
Constraint::Length(1), // Table Name line
Constraint::Length(1), // Table Name line (Input)
Constraint::Length(1), // Spacer
Constraint::Length(1), // Columns Header
Constraint::Min(3), // Columns Table (at least 3 rows visible)
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 Header
Constraint::Min(2), // Indexes Table
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 Header
Constraint::Min(3), // Links Table
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) // Add margin inside the main block
.margin(1) // Margin inside the main block
.split(inner_area);
// --- Helper: Get Border Style based on Focus ---
let get_border_style = |focus: AddTableFocus| {
if add_table_state.current_focus == focus {
focused_style
// 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 {
unfocused_style
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
}
};
// --- 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 ---
// --- 2. Table Name Line (Input) ---
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
.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 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]);
// --- 4. Columns Title ---
f.render_widget(Paragraph::new("Columns").style(title_style), 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]);
// --- 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![
@@ -111,34 +123,37 @@ pub fn render_add_table(
});
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("* "); // Indicate selection
.highlight_symbol("* ");
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 Title ---
f.render_widget(Paragraph::new("Indexes").style(title_style), chunks[7]);
// --- 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]);
// --- 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(
@@ -147,25 +162,24 @@ pub fn render_add_table(
&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]);
// --- 12. Links Title ---
f.render_widget(Paragraph::new("Links (Dependencies)").style(title_style), chunks[11]);
// --- 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]);
// --- 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 " }; // Pad No for alignment
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),
@@ -174,6 +188,7 @@ pub fn render_add_table(
});
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(
@@ -182,28 +197,51 @@ pub fn render_add_table(
&mut add_table_state.link_table_state,
);
// --- 13. Action Buttons ---
// --- 16. Action Buttons ---
let button_layout = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
.split(chunks[12]);
.split(chunks[15]); // Use the last chunk index
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
});
// 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],
);
f.render_widget(save_button, button_layout[0]);
f.render_widget(cancel_button, button_layout[1]);
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],
);
}