// src/functions/modes/navigation/admin_nav.rs use crate::config::binds::config::Config; use crate::state::{ app::state::AppState, pages::admin::{AdminFocus, AdminState}, }; use crossterm::event::KeyEvent; use crate::state::app::buffer::AppView; use crate::state::app::buffer::BufferState; use crate::state::pages::add_table::{AddTableState, LinkDefinition}; use ratatui::widgets::ListState; // --- Helper functions for ListState navigation (similar to TableState) --- 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 => item_count - 1, // Select last if nothing was selected }; list_state.select(Some(i)); } /// Handles navigation events specifically for the Admin Panel view. /// Returns true if the event was handled, false otherwise. pub fn handle_admin_navigation( key: KeyEvent, config: &Config, app_state: &mut AppState, admin_state: &mut AdminState, buffer_state: &mut BufferState, command_message: &mut String, ) -> bool { let action = config.get_general_action(key.code, key.modifiers).map(String::from); // Clone action string let current_focus = admin_state.current_focus; let profile_count = app_state.profile_tree.profiles.len(); let mut new_focus = current_focus; // Start with current focus let mut handled = true; // Assume handled unless logic says otherwise match action.as_deref() { // --- Vertical Navigation (Up/Down) --- Some("move_up") => { match current_focus { AdminFocus::Profiles => { if profile_count > 0 { admin_state.previous_profile(profile_count); *command_message = "Navigated profiles list".to_string(); } } AdminFocus::Tables => { // Navigate highlight when focus is on the block // Updates table navigation state if let Some(nav_profile_idx) = admin_state.profile_list_state.selected() { if let Some(profile) = app_state.profile_tree.profiles.get(nav_profile_idx) { let table_count = profile.tables.len(); if table_count > 0 { admin_state.previous_table(table_count); *command_message = "Navigated tables list".to_string(); } else { *command_message = "No tables in selected profile".to_string(); } } } } AdminFocus::InsideTablesList => { // Scroll inside if let Some(p_idx) = admin_state.profile_list_state.selected().or(admin_state.selected_profile_index) { // Use nav or persistent selection if let Some(profile) = app_state.profile_tree.profiles.get(p_idx) { list_select_previous(&mut admin_state.table_list_state, profile.tables.len()); } } } AdminFocus::Button1 | AdminFocus::Button2 | AdminFocus::Button3 => {} } } Some("move_down") => { match current_focus { AdminFocus::Profiles => { if profile_count > 0 { // Updates navigation state, resets table state admin_state.next_profile(profile_count); *command_message = "Navigated profiles list".to_string(); } } AdminFocus::Tables => { // Navigate highlight when focus is on the block if let Some(nav_profile_idx) = admin_state.profile_list_state.selected() { if let Some(profile) = app_state.profile_tree.profiles.get(nav_profile_idx) { let table_count = profile.tables.len(); if table_count > 0 { admin_state.next_table(table_count); *command_message = "Navigated tables list".to_string(); } } else { *command_message = "No tables in selected profile".to_string(); } } } AdminFocus::InsideTablesList => { // Scroll inside if let Some(p_idx) = admin_state.profile_list_state.selected().or(admin_state.selected_profile_index) { // Use nav or persistent selection if let Some(profile) = app_state.profile_tree.profiles.get(p_idx) { list_select_next(&mut admin_state.table_list_state, profile.tables.len()); } } } AdminFocus::Button1 | AdminFocus::Button2 | AdminFocus::Button3 => {} } } // --- Horizontal Navigation (Focus Change) --- Some("next_option") | Some("previous_option") => { let old_focus = admin_state.current_focus; let is_next = action.as_deref() == Some("next_option"); admin_state.current_focus = match old_focus { AdminFocus::Profiles => if is_next { AdminFocus::Tables } else { AdminFocus::Button3 }, // P -> T (l) or P -> B3 (h) AdminFocus::Tables => if is_next { AdminFocus::Button1 } else { AdminFocus::Profiles }, // T -> B1 (l) or T -> P (h) AdminFocus::Button1 => if is_next { AdminFocus::Button2 } else { AdminFocus::Tables }, // B1 -> B2 (l) or B1 -> T (h) AdminFocus::Button2 => if is_next { AdminFocus::Button3 } else { AdminFocus::Button1 }, // B2 -> B3 (l) or B2 -> B1 (h) AdminFocus::Button3 => if is_next { AdminFocus::Profiles } else { AdminFocus::Button2 }, // B3 -> P (l) or B3 -> B2 (h) // Prevent horizontal nav when inside lists AdminFocus::InsideTablesList => old_focus, }; let new_focus = admin_state.current_focus; *command_message = format!("Focus set to {:?}", new_focus); // Auto-select first item only when moving from Profiles to Tables via 'l' if old_focus == AdminFocus::Profiles && new_focus == AdminFocus::Tables && is_next { if let Some(profile_idx) = admin_state.profile_list_state.selected() { 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); } } else { admin_state.table_list_state.select(None); } } // Clear table nav selection if moving away from Tables if old_focus == AdminFocus::Tables && new_focus != AdminFocus::Tables { admin_state.table_list_state.select(None); } // Clear profile nav selection if moving away from Profiles if old_focus == AdminFocus::Profiles && new_focus != AdminFocus::Profiles { // Maybe keep profile nav highlight? Let's try clearing it. // admin_state.profile_list_state.select(None); // Optional: clear profile nav highlight } } // --- Selection --- Some("select") => { match current_focus { AdminFocus::Profiles => { // --- Perform persistent selection --- // Set the persistent selection to the currently navigated item if let Some(nav_idx) = admin_state.profile_list_state.selected() { admin_state.selected_profile_index = Some(nav_idx); // Move focus to Tables (like pressing 'l') new_focus = AdminFocus::Tables; // Select the first table for navigation highlight admin_state.table_list_state.select(None); // Clear table nav first admin_state.selected_table_index = None; // Clear persistent table selection if let Some(profile) = app_state.profile_tree.profiles.get(nav_idx) { if !profile.tables.is_empty() { admin_state.table_list_state.select(Some(0)); } *command_message = format!("Selected profile: {}", app_state.profile_tree.profiles[nav_idx].name); } } else { *command_message = "No profile selected".to_string(); } } AdminFocus::Tables => { // --- Enter InsideTablesList focus --- new_focus = AdminFocus::InsideTablesList; // Select first item if none selected when entering if let Some(p_idx) = admin_state.profile_list_state.selected().or(admin_state.selected_profile_index) { if let Some(profile) = app_state.profile_tree.profiles.get(p_idx) { if admin_state.table_list_state.selected().is_none() && !profile.tables.is_empty() { admin_state.table_list_state.select(Some(0)); } } } *command_message = "Entered Tables List (Select item with Enter, Exit with Esc)".to_string(); } AdminFocus::InsideTablesList => { // --- Perform persistent selection --- // Set the persistent selection to the currently navigated item if let Some(nav_idx) = admin_state.table_list_state.selected() { admin_state.selected_table_index = Some(nav_idx); // Set persistent selection // Get table name for message let table_name = admin_state.profile_list_state.selected().or(admin_state.selected_profile_index) .and_then(|p_idx| app_state.profile_tree.profiles.get(p_idx)) .and_then(|p| p.tables.get(nav_idx).map(|t| t.name.clone())) .unwrap_or_else(|| "N/A".to_string()); *command_message = format!("Selected table: {}", table_name); } else { *command_message = "No table highlighted".to_string(); } // Stay inside } AdminFocus::Button1 => { *command_message = "Action: Add Logic (Not Implemented)".to_string(); // TODO: Trigger action for Button 1 } AdminFocus::Button2 => { // --- Prepare AddTableState based on persistent selections --- if let Some(p_idx) = admin_state.selected_profile_index { if let Some(profile) = app_state.profile_tree.profiles.get(p_idx) { let selected_profile_name = profile.name.clone(); // Populate links from the selected profile's tables let available_links: Vec = profile .tables .iter() .map(|table| LinkDefinition { linked_table_name: table.name.clone(), is_required: false, // Default selected: false, // Default }) .collect(); // Create and populate the new AddTableState let new_add_table_state = AddTableState { profile_name: selected_profile_name, links: available_links, // Assign populated links ..AddTableState::default() }; // Assign the prepared state admin_state.add_table_state = new_add_table_state; // Switch view buffer_state.update_history(AppView::AddTable); app_state.ui.focus_outside_canvas = false; *command_message = format!( "Navigating to Add Table for profile '{}'...", admin_state.add_table_state.profile_name ); } else { *command_message = "Error: Selected profile index out of bounds.".to_string(); } } else { *command_message = "Please select a profile ([*]) first.".to_string(); } // --- End preparation --- } AdminFocus::Button3 => { *command_message = "Action: Change Table (Not Implemented)".to_string(); // TODO: Trigger action for Button 3 } } } // --- Handle Exiting Inside Mode --- Some("exit_table_scroll") => { // Assuming you have this action bound (e.g., to Esc) match current_focus { AdminFocus::InsideTablesList => { new_focus = AdminFocus::Tables; admin_state.table_list_state.select(None); // Clear nav highlight on exit *command_message = "Exited Tables List".to_string(); } _ => handled = false, // Not applicable } } // --- Other General Keys (Ignore for admin nav) --- Some("toggle_sidebar") | Some("toggle_buffer_list") | Some("next_field") | Some("prev_field") => { // These are handled globally or not applicable here. handled = false; } // --- No matching action --- _ => handled = false, // Event not handled by admin navigation } // Update focus state if it changed and was handled if handled && current_focus != new_focus { admin_state.current_focus = new_focus; // Avoid overwriting specific messages set during 'select' or 'exit' handling if command_message.is_empty() || command_message.starts_with("Focus set to") { *command_message = format!("Focus set to {:?}", admin_state.current_focus); } } else if !handled { // command_message.clear(); // Optional: Clear message if not handled here } handled // Return whether the event was handled by this function }