From 097264040f9f73ef2a225551f2b3d00a7aeb250e Mon Sep 17 00:00:00 2001 From: filipriec Date: Tue, 22 Apr 2025 18:03:22 +0200 Subject: [PATCH] admin_panel for admins have now some adjustements --- .../src/components/admin/admin_panel_admin.rs | 14 +- .../functions/modes/navigation/admin_nav.rs | 159 ++++++++++++++---- client/src/state/pages/admin.rs | 1 + 3 files changed, 130 insertions(+), 44 deletions(-) diff --git a/client/src/components/admin/admin_panel_admin.rs b/client/src/components/admin/admin_panel_admin.rs index fa63365..147a450 100644 --- a/client/src/components/admin/admin_panel_admin.rs +++ b/client/src/components/admin/admin_panel_admin.rs @@ -82,8 +82,8 @@ pub fn render_admin_panel_admin( // Build and render profile list inside the block's inner area let profile_list = List::new(profile_list_items) - // Highlight style depends on focus AND navigation state - .highlight_style(if profile_focus { // Use focus state + // Highlight style depends only on Profiles focus + .highlight_style(if profile_focus { Style::default().add_modifier(ratatui::style::Modifier::REVERSED) } else { Style::default() @@ -93,8 +93,8 @@ pub fn render_admin_panel_admin( f.render_stateful_widget(profile_list, profiles_inner_area, &mut admin_state.profile_list_state); // --- Tables Pane (Middle) --- - let table_focus = admin_state.current_focus == AdminFocus::Tables; - let table_border_style = if table_focus { + let table_pane_has_focus = matches!(admin_state.current_focus, AdminFocus::Tables | AdminFocus::InsideTablesList); + let table_border_style = if table_pane_has_focus { Style::default().fg(theme.highlight) } else { Style::default().fg(theme.border) @@ -157,13 +157,13 @@ pub fn render_admin_panel_admin( // Build and render table list inside the block's inner area let table_list = List::new(table_list_items) - // Highlight style depends on focus AND navigation state - .highlight_style(if table_focus { // Use focus state + // Highlight style depends on whether the pane OR inside has focus + .highlight_style(if table_pane_has_focus { Style::default().add_modifier(ratatui::style::Modifier::REVERSED) } else { Style::default() }) - .highlight_symbol(if table_focus { "> " } else { " " }); // Focus indicator + .highlight_symbol("> "); f.render_stateful_widget(table_list, tables_inner_area, &mut admin_state.table_list_state); diff --git a/client/src/functions/modes/navigation/admin_nav.rs b/client/src/functions/modes/navigation/admin_nav.rs index 389bbc0..436e7ed 100644 --- a/client/src/functions/modes/navigation/admin_nav.rs +++ b/client/src/functions/modes/navigation/admin_nav.rs @@ -9,6 +9,37 @@ 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. @@ -20,36 +51,45 @@ pub fn handle_admin_navigation( buffer_state: &mut BufferState, command_message: &mut String, ) -> bool { - let action = config.get_general_action(key.code, key.modifiers); + 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 { + match action.as_deref() { // --- Vertical Navigation (Up/Down) --- Some("move_up") => { match current_focus { AdminFocus::Profiles => { if profile_count > 0 { - // Updates navigation state, resets table state admin_state.previous_profile(profile_count); - *command_message = "Navigated profiles".to_string(); + *command_message = "Navigated profiles list".to_string(); } } - AdminFocus::Tables => { + 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".to_string(); + *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 => {} } - true // Event handled } Some("move_down") => { match current_focus { @@ -57,29 +97,36 @@ pub fn handle_admin_navigation( if profile_count > 0 { // Updates navigation state, resets table state admin_state.next_profile(profile_count); - *command_message = "Navigated profiles".to_string(); + *command_message = "Navigated profiles list".to_string(); } } - AdminFocus::Tables => { + 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".to_string(); + *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 => {} } - true // Event handled } - // --- Horizontal Navigation (Focus Change) --- Some("next_option") | Some("previous_option") => { let old_focus = admin_state.current_focus; - let is_next = action == Some("next_option"); // Check if 'l' or 'h' + 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) @@ -87,6 +134,8 @@ pub fn handle_admin_navigation( 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; @@ -117,45 +166,63 @@ pub fn handle_admin_navigation( // admin_state.profile_list_state.select(None); // Optional: clear profile nav highlight } - true // Event handled } - // --- 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); // Set persistent selection + admin_state.selected_profile_index = Some(nav_idx); // Move focus to Tables (like pressing 'l') - admin_state.current_focus = AdminFocus::Tables; + 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() { - // Set table nav highlight - admin_state.table_list_state.select(Some(0)); - } - } + if !profile.tables.is_empty() { + admin_state.table_list_state.select(Some(0)); + } - *command_message = format!("Selected profile idx {}, focus on Tables", nav_idx); + *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 - *command_message = format!("Selected table index {}", nav_idx); + // 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(); } - // We don't change focus here for now. + // Stay inside } + AdminFocus::Button1 => { *command_message = "Action: Add Logic (Not Implemented)".to_string(); // TODO: Trigger action for Button 1 @@ -165,24 +232,21 @@ pub fn handle_admin_navigation( 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 Profile Tables --- + // 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, - selected: false, + is_required: false, // Default + selected: false, // Default }) .collect(); - // --- End Populate Links --- - // Create and populate the new AddTableState let new_add_table_state = AddTableState { profile_name: selected_profile_name, - links: available_links, - // Reset other fields to defaults for a fresh start + links: available_links, // Assign populated links ..AddTableState::default() }; @@ -210,16 +274,37 @@ pub fn handle_admin_navigation( // TODO: Trigger action for Button 3 } } - true // Event handled } - + // --- 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. - false + handled = false; } - // --- No matching action --- - _ => false, // Event not handled by admin navigation + _ => 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 } diff --git a/client/src/state/pages/admin.rs b/client/src/state/pages/admin.rs index b8a4093..6f16b16 100644 --- a/client/src/state/pages/admin.rs +++ b/client/src/state/pages/admin.rs @@ -9,6 +9,7 @@ pub enum AdminFocus { #[default] // Default focus is on the profiles list Profiles, Tables, + InsideTablesList, Button1, Button2, Button3,