movement
This commit is contained in:
@@ -5,7 +5,7 @@ use crate::state::{
|
|||||||
pages::add_table::{AddTableFocus, AddTableState},
|
pages::add_table::{AddTableFocus, AddTableState},
|
||||||
};
|
};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
layout::{Alignment, Constraint, Direction, Layout, Rect, Margin},
|
||||||
style::{Modifier, Style, Stylize},
|
style::{Modifier, Style, Stylize},
|
||||||
text::{Line, Span},
|
text::{Line, Span},
|
||||||
widgets::{
|
widgets::{
|
||||||
@@ -14,19 +14,20 @@ use ratatui::{
|
|||||||
Frame,
|
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(
|
pub fn render_add_table(
|
||||||
f: &mut Frame,
|
f: &mut Frame,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
app_state: &AppState,
|
app_state: &AppState, // Read-only access needed
|
||||||
add_table_state: &mut AddTableState,
|
add_table_state: &mut AddTableState, // Mutable for TableState
|
||||||
) {
|
) {
|
||||||
let focused_style = Style::default().fg(theme.highlight);
|
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 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 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 ---
|
||||||
let main_block = Block::default()
|
let main_block = Block::default()
|
||||||
@@ -35,72 +36,83 @@ pub fn render_add_table(
|
|||||||
.border_type(BorderType::Rounded)
|
.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);
|
let inner_area = main_block.inner(area); // Area inside the main border
|
||||||
f.render_widget(main_block, area);
|
f.render_widget(main_block, area);
|
||||||
|
|
||||||
// --- Layout ---
|
// --- Layout (Single Vertical Column) ---
|
||||||
let constraints = [
|
let constraints = [
|
||||||
Constraint::Length(1), // Profile line
|
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), // Spacer
|
||||||
Constraint::Length(1), // Columns Header
|
Constraint::Length(1), // Columns Title
|
||||||
Constraint::Min(3), // Columns Table (at least 3 rows visible)
|
Constraint::Length(2), // Columns Canvas (Placeholder - Height 2)
|
||||||
|
Constraint::Min(3), // Columns Results Table
|
||||||
Constraint::Length(1), // Spacer
|
Constraint::Length(1), // Spacer
|
||||||
Constraint::Length(1), // Indexes Header
|
Constraint::Length(1), // Indexes Title
|
||||||
Constraint::Min(2), // Indexes Table
|
Constraint::Length(2), // Indexes Canvas (Placeholder - Height 2)
|
||||||
|
Constraint::Min(2), // Indexes Results Table
|
||||||
Constraint::Length(1), // Spacer
|
Constraint::Length(1), // Spacer
|
||||||
Constraint::Length(1), // Links Header
|
Constraint::Length(1), // Links Title
|
||||||
Constraint::Min(3), // Links Table
|
Constraint::Length(2), // Links Canvas (Placeholder - Height 2)
|
||||||
|
Constraint::Min(3), // Links Results Table
|
||||||
Constraint::Length(1), // Spacer
|
Constraint::Length(1), // Spacer
|
||||||
Constraint::Length(1), // Action Buttons
|
Constraint::Length(1), // Action Buttons
|
||||||
];
|
];
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints(constraints)
|
.constraints(constraints)
|
||||||
.margin(1) // Add margin inside the main block
|
.margin(1) // Margin inside the main block
|
||||||
.split(inner_area);
|
.split(inner_area);
|
||||||
|
|
||||||
// --- Helper: Get Border Style based on Focus ---
|
// --- Helper: Get Border Style based on Focus ---
|
||||||
let get_border_style = |focus: AddTableFocus| {
|
// Use this for elements that should show focus, like input placeholders or tables
|
||||||
if add_table_state.current_focus == focus {
|
let get_focus_border_style = |focus_target: AddTableFocus| {
|
||||||
focused_style
|
if add_table_state.current_focus == focus_target {
|
||||||
|
Style::default().fg(theme.highlight)
|
||||||
} else {
|
} 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 ---
|
// --- 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);
|
let profile_text = format!("Profile: {}", add_table_state.profile_name);
|
||||||
f.render_widget(Paragraph::new(profile_text).style(base_style), chunks[0]);
|
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()
|
let table_name_block = Block::default()
|
||||||
.borders(Borders::BOTTOM)
|
.borders(Borders::ALL) // Box around input
|
||||||
.border_style(get_border_style(AddTableFocus::TableName));
|
.border_type(BorderType::Plain)
|
||||||
// Basic rendering for now, cursor needs event handling logic
|
.border_style(get_focus_border_style(AddTableFocus::TableName));
|
||||||
let table_name_text = format!("Table Name: [ {} ]", add_table_state.table_name);
|
let table_name_text = format!("Table Name: [ {} ]", add_table_state.table_name);
|
||||||
let table_name_paragraph = Paragraph::new(table_name_text)
|
let table_name_paragraph = Paragraph::new(table_name_text)
|
||||||
.style(base_style)
|
.style(base_style)
|
||||||
.block(table_name_block);
|
.block(table_name_block);
|
||||||
f.render_widget(table_name_paragraph, chunks[1]);
|
f.render_widget(table_name_paragraph, chunks[1]);
|
||||||
|
|
||||||
// --- 4. Columns Header ---
|
// --- 4. Columns Title ---
|
||||||
let columns_header = Paragraph::new(Line::from(vec![
|
f.render_widget(Paragraph::new("Columns").style(title_style), chunks[3]);
|
||||||
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 ---
|
// --- 5. Columns Canvas (Placeholder - No Border, Height 2) ---
|
||||||
let columns_block = Block::default()
|
let columns_canvas_text = Paragraph::new("Name: [input] | Type: [input]")
|
||||||
.borders(Borders::TOP | Borders::BOTTOM) // Only top/bottom for visual separation
|
.style(get_placeholder_style(AddTableFocus::ColumnInput)) // Style text based on focus
|
||||||
.border_style(get_border_style(AddTableFocus::Columns));
|
.alignment(Alignment::Center);
|
||||||
let columns_table_area = columns_block.inner(chunks[4]);
|
f.render_widget(columns_canvas_text, chunks[4]); // Render directly into the chunk
|
||||||
f.render_widget(columns_block, chunks[4]);
|
|
||||||
|
// --- 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| {
|
let column_rows = add_table_state.columns.iter().map(|col| {
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
@@ -111,34 +123,37 @@ pub fn render_add_table(
|
|||||||
});
|
});
|
||||||
let column_widths = [Constraint::Percentage(50), Constraint::Percentage(50)];
|
let column_widths = [Constraint::Percentage(50), Constraint::Percentage(50)];
|
||||||
let columns_table = Table::new(column_rows, column_widths)
|
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_style(selected_row_style)
|
||||||
.highlight_symbol("* "); // Indicate selection
|
.highlight_symbol("* ");
|
||||||
f.render_stateful_widget(
|
f.render_stateful_widget(
|
||||||
columns_table,
|
columns_table,
|
||||||
columns_table_area,
|
columns_table_area,
|
||||||
&mut add_table_state.column_table_state,
|
&mut add_table_state.column_table_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- 7. Indexes Header ---
|
// --- 8. Indexes Title ---
|
||||||
let indexes_header = Paragraph::new(Line::from(vec![
|
f.render_widget(Paragraph::new("Indexes").style(title_style), chunks[7]);
|
||||||
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 ---
|
// --- 9. Indexes Canvas (Placeholder - No Border, Height 2) ---
|
||||||
let indexes_block = Block::default()
|
let indexes_canvas_text = Paragraph::new("Column Name: [input]")
|
||||||
.borders(Borders::TOP | Borders::BOTTOM)
|
.style(get_placeholder_style(AddTableFocus::IndexInput))
|
||||||
.border_style(get_border_style(AddTableFocus::Indexes));
|
.alignment(Alignment::Center);
|
||||||
let indexes_table_area = indexes_block.inner(chunks[7]);
|
f.render_widget(indexes_canvas_text, chunks[8]);
|
||||||
f.render_widget(indexes_block, chunks[7]);
|
|
||||||
|
// --- 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| {
|
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)
|
Row::new(vec![Cell::from(idx_col_name.as_str())]).style(base_style)
|
||||||
});
|
});
|
||||||
let index_widths = [Constraint::Percentage(100)];
|
let index_widths = [Constraint::Percentage(100)];
|
||||||
let indexes_table = Table::new(index_rows, index_widths)
|
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_style(selected_row_style)
|
||||||
.highlight_symbol("* ");
|
.highlight_symbol("* ");
|
||||||
f.render_stateful_widget(
|
f.render_stateful_widget(
|
||||||
@@ -147,25 +162,24 @@ pub fn render_add_table(
|
|||||||
&mut add_table_state.index_table_state,
|
&mut add_table_state.index_table_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- 10. Links Header ---
|
// --- 12. Links Title ---
|
||||||
let links_header = Paragraph::new(Line::from(vec![
|
f.render_widget(Paragraph::new("Links (Dependencies)").style(title_style), chunks[11]);
|
||||||
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 ---
|
// --- 13. Links Canvas (Placeholder - No Border, Height 2) ---
|
||||||
let links_block = Block::default()
|
let links_canvas_text = Paragraph::new("Linked Table: [input] | Required: [ ]")
|
||||||
.borders(Borders::TOP | Borders::BOTTOM)
|
.style(get_placeholder_style(AddTableFocus::LinkInput))
|
||||||
.border_style(get_border_style(AddTableFocus::Links));
|
.alignment(Alignment::Center);
|
||||||
let links_table_area = links_block.inner(chunks[10]);
|
f.render_widget(links_canvas_text, chunks[12]);
|
||||||
f.render_widget(links_block, chunks[10]);
|
|
||||||
|
// --- 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 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![
|
Row::new(vec![
|
||||||
Cell::from(link.linked_table_name.as_str()),
|
Cell::from(link.linked_table_name.as_str()),
|
||||||
Cell::from(required_text),
|
Cell::from(required_text),
|
||||||
@@ -174,6 +188,7 @@ pub fn render_add_table(
|
|||||||
});
|
});
|
||||||
let link_widths = [Constraint::Percentage(70), Constraint::Percentage(30)];
|
let link_widths = [Constraint::Percentage(70), Constraint::Percentage(30)];
|
||||||
let links_table = Table::new(link_rows, link_widths)
|
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_style(selected_row_style)
|
||||||
.highlight_symbol("* ");
|
.highlight_symbol("* ");
|
||||||
f.render_stateful_widget(
|
f.render_stateful_widget(
|
||||||
@@ -182,28 +197,51 @@ pub fn render_add_table(
|
|||||||
&mut add_table_state.link_table_state,
|
&mut add_table_state.link_table_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- 13. Action Buttons ---
|
// --- 16. Action Buttons ---
|
||||||
let button_layout = Layout::default()
|
let button_layout = Layout::default()
|
||||||
.direction(Direction::Horizontal)
|
.direction(Direction::Horizontal)
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
.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 ]")
|
// 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)
|
.alignment(Alignment::Center)
|
||||||
.style(if add_table_state.current_focus == AddTableFocus::SaveButton {
|
.block(
|
||||||
selected_row_style // Use selected style for focused button
|
Block::default()
|
||||||
} else {
|
.borders(Borders::ALL)
|
||||||
base_style
|
.border_type(BorderType::Plain)
|
||||||
});
|
.border_style(save_border),
|
||||||
let cancel_button = Paragraph::new("[ Cancel ]")
|
),
|
||||||
.alignment(Alignment::Center)
|
button_layout[0],
|
||||||
.style(if add_table_state.current_focus == AddTableFocus::CancelButton {
|
);
|
||||||
selected_row_style
|
|
||||||
} else {
|
|
||||||
base_style
|
|
||||||
});
|
|
||||||
|
|
||||||
f.render_widget(save_button, button_layout[0]);
|
let cancel_active = add_table_state.current_focus == AddTableFocus::CancelButton;
|
||||||
f.render_widget(cancel_button, button_layout[1]);
|
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],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
// src/functions/modes/navigation.rs
|
// src/functions/modes/navigation.rs
|
||||||
|
|
||||||
pub mod admin_nav;
|
pub mod admin_nav;
|
||||||
|
pub mod add_table_nav;
|
||||||
|
|||||||
169
client/src/functions/modes/navigation/add_table_nav.rs
Normal file
169
client/src/functions/modes/navigation/add_table_nav.rs
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
// src/functions/modes/navigation/add_table_nav.rs
|
||||||
|
use crate::state::pages::add_table::{AddTableFocus, AddTableState};
|
||||||
|
use crate::state::app::state::AppState; // If needed for list lengths later
|
||||||
|
|
||||||
|
/// Handles navigation events specifically for the Add Table page.
|
||||||
|
/// Returns true if the event was handled, false otherwise.
|
||||||
|
pub fn handle_navigation(
|
||||||
|
state: &mut AddTableState,
|
||||||
|
action: &str,
|
||||||
|
// app_state: &AppState, // Add if needed for list lengths
|
||||||
|
) -> bool {
|
||||||
|
let current_focus = state.current_focus;
|
||||||
|
let mut handled = true; // Assume handled unless proven otherwise
|
||||||
|
|
||||||
|
match action {
|
||||||
|
"move_up" => {
|
||||||
|
state.current_focus = match current_focus {
|
||||||
|
AddTableFocus::TableName => AddTableFocus::CancelButton, // Wrap around top
|
||||||
|
AddTableFocus::ColumnInput => AddTableFocus::TableName,
|
||||||
|
AddTableFocus::ColumnsTable => {
|
||||||
|
// Navigate within table or move focus up
|
||||||
|
if !navigate_table_up(&mut state.column_table_state, state.columns.len()) {
|
||||||
|
state.current_focus = AddTableFocus::ColumnInput;
|
||||||
|
}
|
||||||
|
AddTableFocus::ColumnsTable // Keep focus here while navigating table
|
||||||
|
}
|
||||||
|
AddTableFocus::IndexInput => AddTableFocus::ColumnsTable,
|
||||||
|
AddTableFocus::IndexesTable => {
|
||||||
|
if !navigate_table_up(&mut state.index_table_state, state.indexes.len()) {
|
||||||
|
state.current_focus = AddTableFocus::IndexInput;
|
||||||
|
}
|
||||||
|
AddTableFocus::IndexesTable
|
||||||
|
}
|
||||||
|
AddTableFocus::LinkInput => AddTableFocus::IndexesTable,
|
||||||
|
AddTableFocus::LinksTable => {
|
||||||
|
if !navigate_table_up(&mut state.link_table_state, state.links.len()) {
|
||||||
|
state.current_focus = AddTableFocus::LinkInput;
|
||||||
|
}
|
||||||
|
AddTableFocus::LinksTable
|
||||||
|
}
|
||||||
|
AddTableFocus::SaveButton | AddTableFocus::CancelButton => AddTableFocus::LinksTable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"move_down" => {
|
||||||
|
state.current_focus = match current_focus {
|
||||||
|
AddTableFocus::TableName => AddTableFocus::ColumnInput,
|
||||||
|
AddTableFocus::ColumnInput => AddTableFocus::ColumnsTable,
|
||||||
|
AddTableFocus::ColumnsTable => {
|
||||||
|
if !navigate_table_down(&mut state.column_table_state, state.columns.len()) {
|
||||||
|
state.current_focus = AddTableFocus::IndexInput;
|
||||||
|
}
|
||||||
|
AddTableFocus::ColumnsTable
|
||||||
|
}
|
||||||
|
AddTableFocus::IndexInput => AddTableFocus::IndexesTable,
|
||||||
|
AddTableFocus::IndexesTable => {
|
||||||
|
if !navigate_table_down(&mut state.index_table_state, state.indexes.len()) {
|
||||||
|
state.current_focus = AddTableFocus::LinkInput;
|
||||||
|
}
|
||||||
|
AddTableFocus::IndexesTable
|
||||||
|
}
|
||||||
|
AddTableFocus::LinkInput => AddTableFocus::LinksTable,
|
||||||
|
AddTableFocus::LinksTable => {
|
||||||
|
if !navigate_table_down(&mut state.link_table_state, state.links.len()) {
|
||||||
|
// Move to buttons after table
|
||||||
|
state.current_focus = AddTableFocus::SaveButton;
|
||||||
|
}
|
||||||
|
AddTableFocus::LinksTable
|
||||||
|
}
|
||||||
|
AddTableFocus::SaveButton | AddTableFocus::CancelButton => AddTableFocus::TableName, // Wrap around bottom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"next_option" => { // Typically Tab or Right arrow
|
||||||
|
state.current_focus = match current_focus {
|
||||||
|
// Simple vertical flow for now, like move_down
|
||||||
|
AddTableFocus::TableName => AddTableFocus::ColumnInput,
|
||||||
|
AddTableFocus::ColumnInput => AddTableFocus::ColumnsTable,
|
||||||
|
AddTableFocus::ColumnsTable => AddTableFocus::IndexInput,
|
||||||
|
AddTableFocus::IndexInput => AddTableFocus::IndexesTable,
|
||||||
|
AddTableFocus::IndexesTable => AddTableFocus::LinkInput,
|
||||||
|
AddTableFocus::LinkInput => AddTableFocus::LinksTable,
|
||||||
|
AddTableFocus::LinksTable => AddTableFocus::SaveButton,
|
||||||
|
AddTableFocus::SaveButton => AddTableFocus::CancelButton,
|
||||||
|
AddTableFocus::CancelButton => AddTableFocus::TableName, // Wrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"previous_option" => { // Typically Shift+Tab or Left arrow
|
||||||
|
state.current_focus = match current_focus {
|
||||||
|
// Simple vertical flow upwards
|
||||||
|
AddTableFocus::TableName => AddTableFocus::CancelButton, // Wrap
|
||||||
|
AddTableFocus::ColumnInput => AddTableFocus::TableName,
|
||||||
|
AddTableFocus::ColumnsTable => AddTableFocus::ColumnInput,
|
||||||
|
AddTableFocus::IndexInput => AddTableFocus::ColumnsTable,
|
||||||
|
AddTableFocus::IndexesTable => AddTableFocus::IndexInput,
|
||||||
|
AddTableFocus::LinkInput => AddTableFocus::IndexesTable,
|
||||||
|
AddTableFocus::LinksTable => AddTableFocus::LinkInput,
|
||||||
|
AddTableFocus::SaveButton => AddTableFocus::LinksTable,
|
||||||
|
AddTableFocus::CancelButton => AddTableFocus::SaveButton,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"select" => {
|
||||||
|
// TODO: Implement select action based on current_focus
|
||||||
|
// e.g., Enter edit mode for TableName/Inputs, toggle link required, trigger save/cancel
|
||||||
|
handled = false; // Mark as not handled for now
|
||||||
|
}
|
||||||
|
_ => handled = false, // Action not relevant for this navigation
|
||||||
|
}
|
||||||
|
|
||||||
|
// If focus changed to a table, select the first row if nothing is selected
|
||||||
|
if handled && current_focus != state.current_focus {
|
||||||
|
match state.current_focus {
|
||||||
|
AddTableFocus::ColumnsTable if state.column_table_state.selected().is_none() && !state.columns.is_empty() => {
|
||||||
|
state.column_table_state.select(Some(0));
|
||||||
|
}
|
||||||
|
AddTableFocus::IndexesTable if state.index_table_state.selected().is_none() && !state.indexes.is_empty() => {
|
||||||
|
state.index_table_state.select(Some(0));
|
||||||
|
}
|
||||||
|
AddTableFocus::LinksTable if state.link_table_state.selected().is_none() && !state.links.is_empty() => {
|
||||||
|
state.link_table_state.select(Some(0));
|
||||||
|
}
|
||||||
|
_ => {} // No action needed for other focus states
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
handled
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Helper function for navigating up within a table state
|
||||||
|
// Returns true if navigation happened within the table, false if it reached the top
|
||||||
|
fn navigate_table_up(table_state: &mut ratatui::widgets::TableState, item_count: usize) -> bool {
|
||||||
|
if item_count == 0 { return false; } // Cannot navigate empty table
|
||||||
|
let current_selection = table_state.selected();
|
||||||
|
match current_selection {
|
||||||
|
Some(index) => {
|
||||||
|
if index > 0 {
|
||||||
|
table_state.select(Some(index - 1));
|
||||||
|
true // Moved up within table
|
||||||
|
} else {
|
||||||
|
false // Was at the top
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
table_state.select(Some(item_count - 1)); // Select last item if nothing selected
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function for navigating down within a table state
|
||||||
|
// Returns true if navigation happened within the table, false if it reached the bottom
|
||||||
|
fn navigate_table_down(table_state: &mut ratatui::widgets::TableState, item_count: usize) -> bool {
|
||||||
|
if item_count == 0 { return false; } // Cannot navigate empty table
|
||||||
|
let current_selection = table_state.selected();
|
||||||
|
match current_selection {
|
||||||
|
Some(index) => {
|
||||||
|
if index < item_count - 1 {
|
||||||
|
table_state.select(Some(index + 1));
|
||||||
|
true // Moved down within table
|
||||||
|
} else {
|
||||||
|
false // Was at the bottom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
table_state.select(Some(0)); // Select first item if nothing selected
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,7 +39,7 @@ use crate::modes::{
|
|||||||
highlight::highlight,
|
highlight::highlight,
|
||||||
general::{navigation, dialog},
|
general::{navigation, dialog},
|
||||||
};
|
};
|
||||||
use crate::functions::modes::navigation::admin_nav;
|
use crate::functions::modes::navigation::{admin_nav, add_table_nav};
|
||||||
use crate::config::binds::key_sequences::KeySequenceTracker;
|
use crate::config::binds::key_sequences::KeySequenceTracker;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@@ -175,6 +175,17 @@ impl EventHandler {
|
|||||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// --- Add Table Page Navigation ---
|
||||||
|
if app_state.ui.show_add_table {
|
||||||
|
if let Some(action) = config.get_general_action(key.code, key.modifiers) {
|
||||||
|
if add_table_nav::handle_navigation(
|
||||||
|
&mut admin_state.add_table_state,
|
||||||
|
action,
|
||||||
|
) {
|
||||||
|
return Ok(EventOutcome::Ok(String::new()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let nav_outcome = navigation::handle_navigation_event(
|
let nav_outcome = navigation::handle_navigation_event(
|
||||||
key,
|
key,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ impl ModeManager {
|
|||||||
return AppMode::Highlight;
|
return AppMode::Highlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
if app_state.ui.focus_outside_canvas {
|
if app_state.ui.focus_outside_canvas || app_state.ui.show_add_table{
|
||||||
return AppMode::General;
|
return AppMode::General;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,15 @@ pub struct LinkDefinition {
|
|||||||
pub enum AddTableFocus {
|
pub enum AddTableFocus {
|
||||||
#[default]
|
#[default]
|
||||||
TableName,
|
TableName,
|
||||||
Columns,
|
// Input areas (placeholders for now)
|
||||||
Indexes,
|
ColumnInput,
|
||||||
Links,
|
IndexInput,
|
||||||
|
LinkInput,
|
||||||
|
// Result Tables
|
||||||
|
ColumnsTable,
|
||||||
|
IndexesTable,
|
||||||
|
LinksTable,
|
||||||
|
// Buttons
|
||||||
SaveButton,
|
SaveButton,
|
||||||
CancelButton,
|
CancelButton,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user