413 lines
19 KiB
Rust
413 lines
19 KiB
Rust
// 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<LinkDefinition> = 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
|
|
}
|