// src/pages/admin/main/logic.rs use crate::pages::admin::{AdminFocus, AdminState}; use crate::state::app::state::AppState; use crate::config::binds::config::Config; use crate::buffer::state::{BufferState, AppView}; 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::routing::{Page, Router}; // Helper functions list_select_next and list_select_previous remain the same fn list_select_next(list_state: &mut ListState, item_count: usize) { if item_count == 0 { list_state.select(None); return; } let i = match list_state.selected() { Some(i) => if i >= item_count - 1 { 0 } else { i + 1 }, None => 0, }; list_state.select(Some(i)); } fn list_select_previous(list_state: &mut ListState, item_count: usize) { if item_count == 0 { list_state.select(None); return; } let i = match list_state.selected() { Some(i) => if i == 0 { item_count - 1 } else { i - 1 }, None => if item_count > 0 { item_count - 1 } else { 0 }, }; list_state.select(Some(i)); } pub fn handle_admin_navigation( key: crossterm::event::KeyEvent, config: &Config, app_state: &mut AppState, buffer_state: &mut BufferState, router: &mut Router, command_message: &mut String, ) -> bool { let action = config.get_general_action(key.code, key.modifiers).map(String::from); // Check if we're in admin page, but don't borrow mutably yet let is_admin = matches!(&router.current, Page::Admin(_)); if !is_admin { return false; } // Get the current focus without borrowing mutably let current_focus = if let Page::Admin(admin_state) = &router.current { admin_state.current_focus } else { return false; }; let profile_count = app_state.profile_tree.profiles.len(); let mut handled = false; match current_focus { AdminFocus::ProfilesPane => { // Now we can borrow mutably since we're not reassigning router.current let Page::Admin(admin_state) = &mut router.current else { return false; }; match action.as_deref() { Some("select") => { admin_state.current_focus = AdminFocus::InsideProfilesList; if !app_state.profile_tree.profiles.is_empty() { if admin_state.profile_list_state.selected().is_none() { admin_state.profile_list_state.select(Some(0)); } } *command_message = "Navigating profiles. Use Up/Down. Esc to exit.".to_string(); handled = true; } Some("next_option") | Some("move_down") => { admin_state.current_focus = AdminFocus::Tables; *command_message = "Focus: Tables Pane".to_string(); handled = true; } Some("previous_option") | Some("move_up") => { *command_message = "At first focusable pane.".to_string(); handled = true; } _ => handled = false, } } AdminFocus::InsideProfilesList => { let Page::Admin(admin_state) = &mut router.current else { return false; }; match action.as_deref() { Some("move_up") => { if profile_count > 0 { list_select_previous(&mut admin_state.profile_list_state, profile_count); *command_message = "".to_string(); handled = true; } } Some("move_down") => { if profile_count > 0 { list_select_next(&mut admin_state.profile_list_state, profile_count); *command_message = "".to_string(); handled = true; } } Some("select") => { admin_state.selected_profile_index = admin_state.profile_list_state.selected(); admin_state.selected_table_index = None; if let Some(profile_idx) = admin_state.selected_profile_index { if let Some(profile) = app_state.profile_tree.profiles.get(profile_idx) { if !profile.tables.is_empty() { admin_state.table_list_state.select(Some(0)); } else { admin_state.table_list_state.select(None); } } } else { admin_state.table_list_state.select(None); } *command_message = format!( "Profile '{}' set as active.", admin_state.get_selected_profile_name().unwrap_or(&"N/A".to_string()) ); handled = true; } Some("exit_table_scroll") => { admin_state.current_focus = AdminFocus::ProfilesPane; *command_message = "Focus: Profiles Pane".to_string(); handled = true; } _ => handled = false, } } AdminFocus::Tables => { let Page::Admin(admin_state) = &mut router.current else { return false; }; match action.as_deref() { Some("select") => { admin_state.current_focus = AdminFocus::InsideTablesList; let current_profile_idx = admin_state.selected_profile_index .or_else(|| admin_state.profile_list_state.selected()); if let Some(profile_idx) = current_profile_idx { if let Some(profile) = app_state.profile_tree.profiles.get(profile_idx) { if !profile.tables.is_empty() { if admin_state.table_list_state.selected().is_none() { admin_state.table_list_state.select(Some(0)); } } else { admin_state.table_list_state.select(None); } } else { admin_state.table_list_state.select(None); } } else { admin_state.table_list_state.select(None); *command_message = "Select a profile first to view its tables.".to_string(); } if admin_state.current_focus == AdminFocus::InsideTablesList && !admin_state.table_list_state.selected().is_none() { *command_message = "Navigating tables. Use Up/Down. Esc to exit.".to_string(); } else if admin_state.table_list_state.selected().is_none() { if current_profile_idx.is_none() { *command_message = "No profile selected to view tables.".to_string(); } else { *command_message = "No tables in selected profile.".to_string(); } admin_state.current_focus = AdminFocus::Tables; } handled = true; } Some("previous_option") | Some("move_up") => { admin_state.current_focus = AdminFocus::ProfilesPane; *command_message = "Focus: Profiles Pane".to_string(); handled = true; } Some("next_option") | Some("move_down") => { admin_state.current_focus = AdminFocus::Button1; *command_message = "Focus: Add Logic Button".to_string(); handled = true; } _ => handled = false, } } AdminFocus::InsideTablesList => { let Page::Admin(admin_state) = &mut router.current else { return false; }; match action.as_deref() { Some("move_up") => { let current_profile_idx = admin_state.selected_profile_index .or_else(|| admin_state.profile_list_state.selected()); if let Some(p_idx) = current_profile_idx { if let Some(profile) = app_state.profile_tree.profiles.get(p_idx) { if !profile.tables.is_empty() { list_select_previous(&mut admin_state.table_list_state, profile.tables.len()); *command_message = "".to_string(); handled = true; } else { *command_message = "No tables to navigate.".to_string(); handled = true; } } } else { *command_message = "No active profile for tables.".to_string(); handled = true; } } Some("move_down") => { let current_profile_idx = admin_state.selected_profile_index .or_else(|| admin_state.profile_list_state.selected()); if let Some(p_idx) = current_profile_idx { if let Some(profile) = app_state.profile_tree.profiles.get(p_idx) { if !profile.tables.is_empty() { list_select_next(&mut admin_state.table_list_state, profile.tables.len()); *command_message = "".to_string(); handled = true; } else { *command_message = "No tables to navigate.".to_string(); handled = true; } } } else { *command_message = "No active profile for tables.".to_string(); handled = true; } } Some("select") => { admin_state.selected_table_index = admin_state.table_list_state.selected(); let table_name = admin_state.selected_profile_index .and_then(|p_idx| app_state.profile_tree.profiles.get(p_idx)) .and_then(|p| admin_state.selected_table_index.and_then(|t_idx| p.tables.get(t_idx))) .map_or("N/A", |t| t.name.as_str()); *command_message = format!("Table '{}' set as active.", table_name); handled = true; } Some("exit_table_scroll") => { admin_state.current_focus = AdminFocus::Tables; *command_message = "Focus: Tables Pane".to_string(); handled = true; } _ => handled = false, } } AdminFocus::Button1 => { // Add Logic Button match action.as_deref() { Some("select") => { // Extract needed data first, before any router reassignment let (selected_profile_idx, selected_table_idx) = if let Page::Admin(admin_state) = &router.current { (admin_state.selected_profile_index, admin_state.selected_table_index) } else { return false; }; if let Some(p_idx) = selected_profile_idx { if let Some(profile) = app_state.profile_tree.profiles.get(p_idx) { if let Some(t_idx) = selected_table_idx { if let Some(table) = profile.tables.get(t_idx) { // Create AddLogic page with selected profile & table let add_logic_form = AddLogicFormState::new_with_table( &config.editor, profile.name.clone(), Some(table.id), table.name.clone(), ); // Store table info for later fetching app_state.pending_table_structure_fetch = Some(( profile.name.clone(), table.name.clone(), )); // Now it's safe to reassign router.current router.current = Page::AddLogic(add_logic_form); buffer_state.update_history(AppView::AddLogic); *command_message = format!( "Opening Add Logic for table '{}' in profile '{}'...", table.name, profile.name ); } else { *command_message = "Error: Selected table data not found.".to_string(); } } else { *command_message = "Select a table first!".to_string(); } } else { *command_message = "Error: Selected profile data not found.".to_string(); } } else { *command_message = "Select a profile first!".to_string(); } handled = true; } Some("previous_option") | Some("move_up") => { let Page::Admin(admin_state) = &mut router.current else { return false; }; admin_state.current_focus = AdminFocus::Tables; *command_message = "Focus: Tables Pane".to_string(); handled = true; } Some("next_option") | Some("move_down") => { let Page::Admin(admin_state) = &mut router.current else { return false; }; admin_state.current_focus = AdminFocus::Button2; *command_message = "Focus: Add Table Button".to_string(); handled = true; } _ => handled = false, } } AdminFocus::Button2 => { // Add Table Button match action.as_deref() { Some("select") => { // Extract needed data first let selected_profile_idx = if let Page::Admin(admin_state) = &router.current { admin_state.selected_profile_index } else { return false; }; if let Some(p_idx) = selected_profile_idx { if let Some(profile) = app_state.profile_tree.profiles.get(p_idx) { let selected_profile_name = profile.name.clone(); // Prepare links from the selected profile's existing tables let available_links: Vec = profile.tables.iter() .map(|table| LinkDefinition { linked_table_name: table.name.clone(), is_required: false, selected: false, }).collect(); // Build decoupled AddTable page and route into it let mut page = AddTableFormState::new(selected_profile_name.clone()); page.state.links = available_links; // Now safe to reassign router.current router.current = Page::AddTable(page); buffer_state.update_history(AppView::AddTable); *command_message = format!( "Opening Add Table for profile '{}'...", selected_profile_name ); handled = true; } else { *command_message = "Error: Selected profile index out of bounds.".to_string(); handled = true; } } else { *command_message = "Please select a profile ([*]) first to add a table.".to_string(); handled = true; } } Some("previous_option") | Some("move_up") => { let Page::Admin(admin_state) = &mut router.current else { return false; }; admin_state.current_focus = AdminFocus::Button1; *command_message = "Focus: Add Logic Button".to_string(); handled = true; } Some("next_option") | Some("move_down") => { let Page::Admin(admin_state) = &mut router.current else { return false; }; admin_state.current_focus = AdminFocus::Button3; *command_message = "Focus: Change Table Button".to_string(); handled = true; } _ => handled = false, } } AdminFocus::Button3 => { // Change Table Button match action.as_deref() { Some("select") => { *command_message = "Action: Change Table (Not Implemented)".to_string(); handled = true; } Some("previous_option") | Some("move_up") => { let Page::Admin(admin_state) = &mut router.current else { return false; }; admin_state.current_focus = AdminFocus::Button2; *command_message = "Focus: Add Table Button".to_string(); handled = true; } Some("next_option") | Some("move_down") => { *command_message = "At last focusable button.".to_string(); handled = true; } _ => handled = false, } } } handled }