add table and add logic removal from ui.rs and event.rs

This commit is contained in:
filipriec
2025-08-30 19:47:26 +02:00
parent 9ed558562b
commit c7d524c76a
6 changed files with 179 additions and 76 deletions

View File

@@ -460,22 +460,6 @@ impl EventHandler {
// Let the current page handle decoupled movement first
if let Some(ma) = movement_action {
match &mut router.current {
// LOGIN: From buttons (general) back into the canvas with 'k' (Up),
// but ONLY from the left-most "Login" button.
Page::AddTable(state) => {
if state.handle_movement(ma) {
// Keep UI focus consistent with inputs vs. outer elements
use crate::pages::admin_panel::add_table::state::AddTableFocus;
let is_canvas_input = matches!(
state.current_focus,
AddTableFocus::InputTableName
| AddTableFocus::InputColumnName
| AddTableFocus::InputColumnType
);
app_state.ui.focus_outside_canvas = !is_canvas_input;
return Ok(EventOutcome::Ok(String::new()));
}
}
Page::Intro(state) => {
if state.handle_movement(ma) {
return Ok(EventOutcome::Ok(String::new()));
@@ -506,8 +490,9 @@ impl EventHandler {
if let Page::AddTable(add_table_state) = &mut router.current {
let client_clone = self.grpc_client.clone();
let sender_clone = self.save_table_result_sender.clone();
if add_table::nav::handle_add_table_navigation(
if crate::pages::admin_panel::add_table::event::handle_add_table_event(
key_event,
movement_action, // wrapper handles both movement + nav
config,
app_state,
add_table_state,
@@ -515,9 +500,7 @@ impl EventHandler {
sender_clone,
&mut self.command_message,
) {
return Ok(EventOutcome::Ok(
self.command_message.clone(),
));
return Ok(EventOutcome::Ok(self.command_message.clone()));
}
}

View File

@@ -0,0 +1,108 @@
// src/pages/admin_panel/add_logic/loader.rs
use anyhow::{Context, Result};
use tracing::{error, info, warn};
use crate::pages::admin_panel::add_logic::state::AddLogicState;
use crate::pages::routing::{Page, Router};
use crate::services::grpc_client::GrpcClient;
use crate::services::ui_service::UiService;
use crate::state::app::state::AppState;
/// Process pending table structure fetch for AddLogic page.
/// Returns true if UI needs a redraw.
pub async fn process_pending_table_structure_fetch(
app_state: &mut AppState,
router: &mut Router,
grpc_client: &mut GrpcClient,
command_message: &mut String,
) -> Result<bool> {
let mut needs_redraw = false;
if let Some((profile_name, table_name)) = app_state.pending_table_structure_fetch.take() {
if let Page::AddLogic(state) = &mut router.current {
if state.profile_name == profile_name
&& state.selected_table_name.as_deref() == Some(table_name.as_str())
{
info!(
"Fetching table structure for {}.{}",
profile_name, table_name
);
let fetch_message = UiService::initialize_add_logic_table_data(
grpc_client,
state,
&app_state.profile_tree,
)
.await
.unwrap_or_else(|e| {
error!(
"Error initializing add_logic_table_data for {}.{}: {}",
profile_name, table_name, e
);
format!("Error fetching table structure: {}", e)
});
if !fetch_message.contains("Error") && !fetch_message.contains("Warning") {
info!("{}", fetch_message);
} else {
*command_message = fetch_message;
}
needs_redraw = true;
} else {
error!(
"Mismatch in pending_table_structure_fetch: app_state wants {}.{}, \
but AddLogic state is for {}.{:?}",
profile_name, table_name, state.profile_name, state.selected_table_name
);
}
} else {
warn!(
"Pending table structure fetch for {}.{} but AddLogic view is not active. Ignored.",
profile_name, table_name
);
}
}
Ok(needs_redraw)
}
/// If the AddLogic page is awaiting columns for a selected table in the script editor,
/// fetch them and update the state. Returns true if UI needs a redraw.
pub async fn maybe_fetch_columns_for_awaiting_table(
grpc_client: &mut GrpcClient,
state: &mut AddLogicState,
command_message: &mut String,
) -> Result<bool> {
if let Some(table_name) = state
.script_editor_awaiting_column_autocomplete
.clone()
{
let profile_name = state.profile_name.clone();
info!(
"Fetching columns for table selection: {}.{}",
profile_name, table_name
);
match UiService::fetch_columns_for_table(grpc_client, &profile_name, &table_name).await {
Ok(columns) => {
state.set_columns_for_table_autocomplete(columns.clone());
info!("Loaded {} columns for table '{}'", columns.len(), table_name);
*command_message =
format!("Columns for '{}' loaded. Select a column.", table_name);
}
Err(e) => {
error!(
"Failed to fetch columns for {}.{}: {}",
profile_name, table_name, e
);
state.script_editor_awaiting_column_autocomplete = None;
state.deactivate_script_editor_autocomplete();
*command_message = format!("Error loading columns for '{}': {}", table_name, e);
}
}
return Ok(true);
}
Ok(false)
}

View File

@@ -3,3 +3,4 @@
pub mod ui;
pub mod nav;
pub mod state;
pub mod loader;

View File

@@ -0,0 +1,51 @@
// src/pages/admin_panel/add_table/event.rs
use crate::config::binds::config::Config;
use crate::movement::MovementAction;
use crate::pages::admin_panel::add_table::nav;
use crate::pages::admin_panel::add_table::nav::SaveTableResultSender;
use crate::pages::admin_panel::add_table::state::{AddTableFocus, AddTableState};
use crate::services::GrpcClient;
use crate::state::app::state::AppState;
use crossterm::event::KeyEvent;
/// Handle all AddTable page-specific events in one place.
/// - First try movement actions (Up/Down/Select/Esc) via AddTableState::handle_movement
/// - Then, if not handled, try rich actions via nav::handle_add_table_navigation
///
/// Returns true if the key was handled (caller should stop propagation).
pub fn handle_add_table_event(
key_event: KeyEvent,
movement_action: Option<MovementAction>,
config: &Config,
app_state: &mut AppState,
state: &mut AddTableState,
grpc_client: GrpcClient,
save_result_sender: SaveTableResultSender,
command_message: &mut String,
) -> bool {
// 1) Try movement first (keeps focus cycling consistent)
if let Some(ma) = movement_action {
if state.handle_movement(ma) {
let is_canvas_input = matches!(
state.current_focus,
AddTableFocus::InputTableName
| AddTableFocus::InputColumnName
| AddTableFocus::InputColumnType
);
app_state.ui.focus_outside_canvas = !is_canvas_input;
return true;
}
}
// 2) Rich actions/navigation for AddTable
nav::handle_add_table_navigation(
key_event,
config,
app_state,
state,
grpc_client,
save_result_sender,
command_message,
)
}

View File

@@ -4,3 +4,4 @@ pub mod ui;
pub mod nav;
pub mod state;
pub mod logic;
pub mod event;

View File

@@ -12,6 +12,7 @@ use crate::state::pages::auth::AuthState;
use crate::state::pages::auth::UserRole;
use crate::pages::login::LoginFormState;
use crate::pages::register::RegisterFormState;
use crate::pages::admin_panel::add_logic;
use crate::pages::admin::AdminState;
use crate::pages::admin::AdminFocus;
use crate::pages::admin::admin;
@@ -485,67 +486,25 @@ pub async fn run_ui() -> Result<()> {
}
}
// Continue with the rest of the positioning logic...
// Now we can use CanvasState methods like get_current_input(), current_field(), etc.
let needs_redraw_from_fetch = add_logic::loader::process_pending_table_structure_fetch(
&mut app_state,
&mut router,
&mut grpc_client,
&mut event_handler.command_message,
).await.unwrap_or(false);
if needs_redraw_from_fetch {
needs_redraw = true;
}
if let Some((profile_name, table_name)) = app_state.pending_table_structure_fetch.take() {
if let Page::AddLogic(state) = &mut router.current {
if state.profile_name == profile_name
&& state.selected_table_name.as_deref() == Some(table_name.as_str())
{
info!("Fetching table structure for {}.{}", profile_name, table_name);
let fetch_message = UiService::initialize_add_logic_table_data(
let needs_redraw_from_columns = add_logic::loader::maybe_fetch_columns_for_awaiting_table(
&mut grpc_client,
state,
&app_state.profile_tree,
)
.await
.unwrap_or_else(|e| {
error!("Error initializing add_logic_table_data: {}", e);
format!("Error fetching table structure: {}", e)
});
&mut event_handler.command_message,
).await.unwrap_or(false);
if !fetch_message.contains("Error") && !fetch_message.contains("Warning") {
info!("{}", fetch_message);
} else {
event_handler.command_message = fetch_message;
}
needs_redraw = true;
} else {
error!(
"Mismatch in pending_table_structure_fetch: app_state wants {}.{}, but AddLogic state is for {}.{:?}",
profile_name,
table_name,
state.profile_name,
state.selected_table_name
);
}
} else {
warn!(
"Pending table structure fetch for {}.{} but AddLogic view is not active. Fetch ignored.",
profile_name, table_name
);
}
}
if let Page::AddLogic(state) = &mut router.current {
if let Some(table_name) = state.script_editor_awaiting_column_autocomplete.clone() {
let profile_name = state.profile_name.clone();
info!("Fetching columns for table selection: {}.{}", profile_name, table_name);
match UiService::fetch_columns_for_table(&mut grpc_client, &profile_name, &table_name).await {
Ok(columns) => {
state.set_columns_for_table_autocomplete(columns.clone());
info!("Loaded {} columns for table '{}'", columns.len(), table_name);
event_handler.command_message = format!("Columns for '{}' loaded. Select a column.", table_name);
}
Err(e) => {
error!("Failed to fetch columns for {}.{}: {}", profile_name, table_name, e);
state.script_editor_awaiting_column_autocomplete = None;
state.deactivate_script_editor_autocomplete();
event_handler.command_message = format!("Error loading columns for '{}': {}", table_name, e);
}
}
if needs_redraw_from_columns {
needs_redraw = true;
}
}