moving add_table to add_logic modern architecture2
This commit is contained in:
@@ -154,15 +154,14 @@ pub async fn handle_dialog_event(
|
|||||||
DialogPurpose::ConfirmDeleteColumns => match selected_index {
|
DialogPurpose::ConfirmDeleteColumns => match selected_index {
|
||||||
0 => {
|
0 => {
|
||||||
// "Confirm" button selected
|
// "Confirm" button selected
|
||||||
if let Page::Admin(state) = &mut router.current {
|
if let Page::AddTable(page) = &mut router.current {
|
||||||
let outcome_message =
|
let outcome_message = handle_delete_selected_columns(&mut page.state);
|
||||||
handle_delete_selected_columns(&mut state.add_table_state);
|
|
||||||
app_state.hide_dialog();
|
app_state.hide_dialog();
|
||||||
return Some(Ok(EventOutcome::Ok(outcome_message)));
|
return Some(Ok(EventOutcome::Ok(outcome_message)));
|
||||||
}
|
}
|
||||||
return Some(Ok(EventOutcome::Ok(
|
return Some(Ok(EventOutcome::Ok(
|
||||||
"Admin state not active".to_string(),
|
"AddTable page not active".to_string(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
// "Cancel" button selected
|
// "Cancel" button selected
|
||||||
|
|||||||
@@ -379,6 +379,24 @@ impl EventHandler {
|
|||||||
return Ok(outcome);
|
return Ok(outcome);
|
||||||
}
|
}
|
||||||
} else if let Page::AddTable(add_table_page) = &mut router.current {
|
} else if let Page::AddTable(add_table_page) = &mut router.current {
|
||||||
|
// Allow ":" (enter_command_mode) even when inside AddTable canvas
|
||||||
|
if let Some(action) =
|
||||||
|
config.get_general_action(key_event.code, key_event.modifiers)
|
||||||
|
{
|
||||||
|
if action == "enter_command_mode"
|
||||||
|
&& !self.command_mode
|
||||||
|
&& !app_state.ui.show_search_palette
|
||||||
|
&& !self.navigation_state.active
|
||||||
|
{
|
||||||
|
self.command_mode = true;
|
||||||
|
self.command_input.clear();
|
||||||
|
self.command_message.clear();
|
||||||
|
self.key_sequence_tracker.reset();
|
||||||
|
app_state.ui.focus_outside_canvas = true;
|
||||||
|
return Ok(EventOutcome::Ok(String::new()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle AddTable before global actions so canvas gets first shot at keys.
|
// Handle AddTable before global actions so canvas gets first shot at keys.
|
||||||
// Map keys to MovementAction (same as AddLogic early handler)
|
// Map keys to MovementAction (same as AddLogic early handler)
|
||||||
let movement_action_early = if let Some(act) =
|
let movement_action_early = if let Some(act) =
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// src/pages/admin/admin/state.rs
|
// src/pages/admin/admin/state.rs
|
||||||
use ratatui::widgets::ListState;
|
use ratatui::widgets::ListState;
|
||||||
use crate::pages::admin_panel::add_table::state::AddTableState;
|
|
||||||
use crate::movement::{move_focus, MovementAction};
|
use crate::movement::{move_focus, MovementAction};
|
||||||
use crate::state::app::state::AppState;
|
use crate::state::app::state::AppState;
|
||||||
|
|
||||||
@@ -26,7 +25,6 @@ pub struct AdminState {
|
|||||||
pub selected_profile_index: Option<usize>,
|
pub selected_profile_index: Option<usize>,
|
||||||
pub selected_table_index: Option<usize>,
|
pub selected_table_index: Option<usize>,
|
||||||
pub current_focus: AdminFocus,
|
pub current_focus: AdminFocus,
|
||||||
pub add_table_state: AddTableState,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AdminState {
|
impl AdminState {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use crate::pages::admin::{AdminFocus, AdminState};
|
|||||||
use crate::state::app::state::AppState;
|
use crate::state::app::state::AppState;
|
||||||
use crate::config::binds::config::Config;
|
use crate::config::binds::config::Config;
|
||||||
use crate::buffer::state::{BufferState, AppView};
|
use crate::buffer::state::{BufferState, AppView};
|
||||||
use crate::pages::admin_panel::add_table::state::{AddTableState, LinkDefinition};
|
|
||||||
use ratatui::widgets::ListState;
|
use ratatui::widgets::ListState;
|
||||||
|
use crate::pages::admin_panel::add_table::state::{AddTableFormState, LinkDefinition};
|
||||||
use crate::pages::admin_panel::add_logic::state::{AddLogicState, AddLogicFocus, AddLogicFormState};
|
use crate::pages::admin_panel::add_logic::state::{AddLogicState, AddLogicFocus, AddLogicFormState};
|
||||||
use crate::pages::routing::{Page, Router};
|
use crate::pages::routing::{Page, Router};
|
||||||
|
|
||||||
@@ -299,14 +299,16 @@ pub fn handle_admin_navigation(
|
|||||||
selected: false,
|
selected: false,
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
admin_state.add_table_state = AddTableState {
|
// Build decoupled AddTable page and route into it
|
||||||
profile_name: selected_profile_name,
|
let mut page = AddTableFormState::new(selected_profile_name.clone());
|
||||||
links: available_links,
|
page.state.links = available_links;
|
||||||
..AddTableState::default() // Reset other fields
|
router.current = Page::AddTable(page);
|
||||||
};
|
|
||||||
buffer_state.update_history(AppView::AddTable);
|
buffer_state.update_history(AppView::AddTable);
|
||||||
app_state.ui.focus_outside_canvas = false;
|
app_state.ui.focus_outside_canvas = false;
|
||||||
*command_message = format!("Opening Add Table for profile '{}'...", admin_state.add_table_state.profile_name);
|
*command_message = format!(
|
||||||
|
"Opening Add Table for profile '{}'...",
|
||||||
|
selected_profile_name
|
||||||
|
);
|
||||||
handled = true;
|
handled = true;
|
||||||
} else {
|
} else {
|
||||||
*command_message = "Error: Selected profile index out of bounds.".to_string();
|
*command_message = "Error: Selected profile index out of bounds.".to_string();
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use canvas::{DataProvider, AppMode};
|
|||||||
use canvas::FormEditor;
|
use canvas::FormEditor;
|
||||||
use ratatui::widgets::TableState;
|
use ratatui::widgets::TableState;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::movement::{move_focus, MovementAction};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct ColumnDefinition {
|
pub struct ColumnDefinition {
|
||||||
@@ -211,178 +210,6 @@ impl DataProvider for AddTableState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl AddTableState {
|
|
||||||
pub fn handle_movement(&mut self, action: MovementAction) -> bool {
|
|
||||||
use AddTableFocus::*;
|
|
||||||
|
|
||||||
// Linear outer focus order
|
|
||||||
const ORDER: [AddTableFocus; 10] = [
|
|
||||||
InputTableName,
|
|
||||||
InputColumnName,
|
|
||||||
InputColumnType,
|
|
||||||
AddColumnButton,
|
|
||||||
ColumnsTable,
|
|
||||||
IndexesTable,
|
|
||||||
LinksTable,
|
|
||||||
SaveButton,
|
|
||||||
DeleteSelectedButton,
|
|
||||||
CancelButton,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Enter "inside" on Select from outer panes
|
|
||||||
match (self.current_focus, action) {
|
|
||||||
(ColumnsTable, MovementAction::Select) => {
|
|
||||||
if !self.columns.is_empty() && self.column_table_state.selected().is_none() {
|
|
||||||
self.column_table_state.select(Some(0));
|
|
||||||
}
|
|
||||||
self.current_focus = InsideColumnsTable;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
(IndexesTable, MovementAction::Select) => {
|
|
||||||
if !self.indexes.is_empty() && self.index_table_state.selected().is_none() {
|
|
||||||
self.index_table_state.select(Some(0));
|
|
||||||
}
|
|
||||||
self.current_focus = InsideIndexesTable;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
(LinksTable, MovementAction::Select) => {
|
|
||||||
if !self.links.is_empty() && self.link_table_state.selected().is_none() {
|
|
||||||
self.link_table_state.select(Some(0));
|
|
||||||
}
|
|
||||||
self.current_focus = InsideLinksTable;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle "inside" states: Up/Down/Select/Esc; block outer movement keys
|
|
||||||
match self.current_focus {
|
|
||||||
InsideColumnsTable => {
|
|
||||||
match action {
|
|
||||||
MovementAction::Up => {
|
|
||||||
if let Some(i) = self.column_table_state.selected() {
|
|
||||||
let next = i.saturating_sub(1);
|
|
||||||
self.column_table_state.select(Some(next));
|
|
||||||
} else if !self.columns.is_empty() {
|
|
||||||
self.column_table_state.select(Some(0));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Down => {
|
|
||||||
if let Some(i) = self.column_table_state.selected() {
|
|
||||||
let last = self.columns.len().saturating_sub(1);
|
|
||||||
let next = if i < last { i + 1 } else { i };
|
|
||||||
self.column_table_state.select(Some(next));
|
|
||||||
} else if !self.columns.is_empty() {
|
|
||||||
self.column_table_state.select(Some(0));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Select => {
|
|
||||||
if let Some(i) = self.column_table_state.selected() {
|
|
||||||
if let Some(col) = self.columns.get_mut(i) {
|
|
||||||
col.selected = !col.selected;
|
|
||||||
self.has_unsaved_changes = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Esc => {
|
|
||||||
self.column_table_state.select(None);
|
|
||||||
self.current_focus = ColumnsTable;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Next | MovementAction::Previous => return true, // block outer moves
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InsideIndexesTable => {
|
|
||||||
match action {
|
|
||||||
MovementAction::Up => {
|
|
||||||
if let Some(i) = self.index_table_state.selected() {
|
|
||||||
let next = i.saturating_sub(1);
|
|
||||||
self.index_table_state.select(Some(next));
|
|
||||||
} else if !self.indexes.is_empty() {
|
|
||||||
self.index_table_state.select(Some(0));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Down => {
|
|
||||||
if let Some(i) = self.index_table_state.selected() {
|
|
||||||
let last = self.indexes.len().saturating_sub(1);
|
|
||||||
let next = if i < last { i + 1 } else { i };
|
|
||||||
self.index_table_state.select(Some(next));
|
|
||||||
} else if !self.indexes.is_empty() {
|
|
||||||
self.index_table_state.select(Some(0));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Select => {
|
|
||||||
if let Some(i) = self.index_table_state.selected() {
|
|
||||||
if let Some(ix) = self.indexes.get_mut(i) {
|
|
||||||
ix.selected = !ix.selected;
|
|
||||||
self.has_unsaved_changes = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Esc => {
|
|
||||||
self.index_table_state.select(None);
|
|
||||||
self.current_focus = IndexesTable;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Next | MovementAction::Previous => return true, // block outer moves
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InsideLinksTable => {
|
|
||||||
match action {
|
|
||||||
MovementAction::Up => {
|
|
||||||
if let Some(i) = self.link_table_state.selected() {
|
|
||||||
let next = i.saturating_sub(1);
|
|
||||||
self.link_table_state.select(Some(next));
|
|
||||||
} else if !self.links.is_empty() {
|
|
||||||
self.link_table_state.select(Some(0));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Down => {
|
|
||||||
if let Some(i) = self.link_table_state.selected() {
|
|
||||||
let last = self.links.len().saturating_sub(1);
|
|
||||||
let next = if i < last { i + 1 } else { i };
|
|
||||||
self.link_table_state.select(Some(next));
|
|
||||||
} else if !self.links.is_empty() {
|
|
||||||
self.link_table_state.select(Some(0));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Select => {
|
|
||||||
if let Some(i) = self.link_table_state.selected() {
|
|
||||||
if let Some(link) = self.links.get_mut(i) {
|
|
||||||
link.selected = !link.selected;
|
|
||||||
self.has_unsaved_changes = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Esc => {
|
|
||||||
self.link_table_state.select(None);
|
|
||||||
self.current_focus = LinksTable;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MovementAction::Next | MovementAction::Previous => return true, // block outer moves
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default: outer navigation via helper
|
|
||||||
move_focus(&ORDER, &mut self.current_focus, action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AddTableFormState {
|
pub struct AddTableFormState {
|
||||||
pub state: AddTableState,
|
pub state: AddTableState,
|
||||||
pub editor: FormEditor<AddTableState>,
|
pub editor: FormEditor<AddTableState>,
|
||||||
|
|||||||
@@ -366,7 +366,9 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
vec!["OK".to_string()],
|
vec!["OK".to_string()],
|
||||||
DialogPurpose::SaveTableSuccess,
|
DialogPurpose::SaveTableSuccess,
|
||||||
);
|
);
|
||||||
admin_state.add_table_state.has_unsaved_changes = false;
|
if let Page::AddTable(page) = &mut router.current {
|
||||||
|
page.state.has_unsaved_changes = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
event_handler.command_message = format!("Save failed: {}", e);
|
event_handler.command_message = format!("Save failed: {}", e);
|
||||||
@@ -426,14 +428,11 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
router.navigate(Page::Admin(admin_state.clone()));
|
router.navigate(Page::Admin(admin_state.clone()));
|
||||||
}
|
}
|
||||||
AppView::AddTable => {
|
AppView::AddTable => {
|
||||||
if let Page::AddTable(_) = &router.current {
|
if let Page::AddTable(page) = &mut router.current {
|
||||||
} else {
|
// Ensure keymap is set once (same as AddLogic)
|
||||||
let mut page =
|
|
||||||
add_table::state::AddTableFormState::from_state(
|
|
||||||
admin_state.add_table_state.clone(),
|
|
||||||
);
|
|
||||||
page.editor.set_keymap(config.build_canvas_keymap());
|
page.editor.set_keymap(config.build_canvas_keymap());
|
||||||
router.navigate(Page::AddTable(page));
|
} else {
|
||||||
|
// Page is created by admin navigation (Button2). No-op here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AppView::AddLogic => {
|
AppView::AddLogic => {
|
||||||
|
|||||||
Reference in New Issue
Block a user