Compare commits
2 Commits
ab81434c4e
...
8157dc7a60
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8157dc7a60 | ||
|
|
3b130e9208 |
@@ -378,6 +378,40 @@ impl EventHandler {
|
|||||||
if !outcome.get_message_if_ok().is_empty() {
|
if !outcome.get_message_if_ok().is_empty() {
|
||||||
return Ok(outcome);
|
return Ok(outcome);
|
||||||
}
|
}
|
||||||
|
} else if let Page::AddTable(add_table_page) = &mut router.current {
|
||||||
|
// Handle AddTable before global actions so canvas gets first shot at keys.
|
||||||
|
// Map keys to MovementAction (same as AddLogic early handler)
|
||||||
|
let movement_action_early = if let Some(act) =
|
||||||
|
config.get_general_action(key_event.code, key_event.modifiers)
|
||||||
|
{
|
||||||
|
match act {
|
||||||
|
"up" => Some(MovementAction::Up),
|
||||||
|
"down" => Some(MovementAction::Down),
|
||||||
|
"left" => Some(MovementAction::Left),
|
||||||
|
"right" => Some(MovementAction::Right),
|
||||||
|
"next" => Some(MovementAction::Next),
|
||||||
|
"previous" => Some(MovementAction::Previous),
|
||||||
|
"select" => Some(MovementAction::Select),
|
||||||
|
"esc" => Some(MovementAction::Esc),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let outcome = add_table::event::handle_add_table_event(
|
||||||
|
key_event,
|
||||||
|
movement_action_early,
|
||||||
|
config,
|
||||||
|
app_state,
|
||||||
|
add_table_page,
|
||||||
|
self.grpc_client.clone(),
|
||||||
|
self.save_table_result_sender.clone(),
|
||||||
|
)?;
|
||||||
|
// Only stop if the page consumed the key; else let global handling proceed.
|
||||||
|
if !outcome.get_message_if_ok().is_empty() {
|
||||||
|
return Ok(outcome);
|
||||||
|
}
|
||||||
} else if let Page::Admin(admin_state) = &mut router.current {
|
} else if let Page::Admin(admin_state) = &mut router.current {
|
||||||
if matches!(auth_state.role, Some(UserRole::Admin)) {
|
if matches!(auth_state.role, Some(UserRole::Admin)) {
|
||||||
if let Event::Key(key_event) = event {
|
if let Event::Key(key_event) = event {
|
||||||
@@ -531,23 +565,6 @@ 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();
|
|
||||||
let outcome = crate::pages::admin_panel::add_table::event::handle_add_table_event(
|
|
||||||
key_event,
|
|
||||||
movement_action,
|
|
||||||
config,
|
|
||||||
app_state,
|
|
||||||
add_table_state,
|
|
||||||
client_clone,
|
|
||||||
sender_clone,
|
|
||||||
)?;
|
|
||||||
if !outcome.get_message_if_ok().is_empty() {
|
|
||||||
return Ok(outcome);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic navigation for the rest (Intro/Login/Register/Form)
|
// Generic navigation for the rest (Intro/Login/Register/Form)
|
||||||
let nav_outcome = if matches!(&router.current, Page::AddTable(_) | Page::AddLogic(_)) {
|
let nav_outcome = if matches!(&router.current, Page::AddTable(_) | Page::AddLogic(_)) {
|
||||||
// Skip generic navigation for AddTable/AddLogic (they have their own handlers)
|
// Skip generic navigation for AddTable/AddLogic (they have their own handlers)
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ use crate::pages::admin_panel::add_table::logic::{
|
|||||||
};
|
};
|
||||||
use crate::pages::admin_panel::add_table::nav::SaveTableResultSender;
|
use crate::pages::admin_panel::add_table::nav::SaveTableResultSender;
|
||||||
use crate::pages::admin_panel::add_table::state::{AddTableFocus, AddTableFormState};
|
use crate::pages::admin_panel::add_table::state::{AddTableFocus, AddTableFormState};
|
||||||
use crate::services::GrpcClient;
|
use crate::services::grpc_client::GrpcClient;
|
||||||
use crate::state::app::state::AppState;
|
use crate::state::app::state::AppState;
|
||||||
use crate::modes::handlers::event::EventOutcome;
|
use crate::modes::handlers::event::EventOutcome;
|
||||||
|
use canvas::{AppMode as CanvasMode, DataProvider};
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
|
|
||||||
/// Focus traversal order for AddTable (outside canvas)
|
/// Focus traversal order for AddTable (outside canvas)
|
||||||
@@ -24,11 +25,13 @@ const ADD_TABLE_FOCUS_ORDER: [AddTableFocus; 7] = [
|
|||||||
AddTableFocus::CancelButton,
|
AddTableFocus::CancelButton,
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Unified AddTable event handler (like AddLogic)
|
/// Handles all AddTable page-specific events.
|
||||||
|
/// Return a non-empty Ok(message) only when the page actually consumed the key,
|
||||||
|
/// otherwise return Ok("") to let global handling proceed.
|
||||||
pub fn handle_add_table_event(
|
pub fn handle_add_table_event(
|
||||||
key_event: KeyEvent,
|
key_event: KeyEvent,
|
||||||
movement: Option<MovementAction>,
|
movement: Option<MovementAction>,
|
||||||
_config: &Config,
|
config: &Config,
|
||||||
app_state: &mut AppState,
|
app_state: &mut AppState,
|
||||||
page: &mut AddTableFormState,
|
page: &mut AddTableFormState,
|
||||||
mut grpc_client: GrpcClient,
|
mut grpc_client: GrpcClient,
|
||||||
@@ -43,6 +46,36 @@ pub fn handle_add_table_event(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if inside_canvas_inputs {
|
if inside_canvas_inputs {
|
||||||
|
// Disable global shortcuts while typing
|
||||||
|
app_state.ui.focus_outside_canvas = false;
|
||||||
|
|
||||||
|
// Special case: allow ":" to enter command mode even inside canvas
|
||||||
|
if let Some(action) = config.get_general_action(key_event.code, key_event.modifiers) {
|
||||||
|
if action == "enter_command_mode"
|
||||||
|
&& !app_state.ui.show_search_palette
|
||||||
|
&& !app_state.ui.dialog.dialog_show
|
||||||
|
{
|
||||||
|
app_state.ui.focus_outside_canvas = true;
|
||||||
|
return Ok(EventOutcome::Ok(String::new()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only allow leaving the canvas with Down/Next when in ReadOnly mode
|
||||||
|
let in_edit_mode = page.editor.mode() == CanvasMode::Edit;
|
||||||
|
if !in_edit_mode {
|
||||||
|
if let Some(ma) = movement {
|
||||||
|
let last_idx = page.editor.data_provider().field_count().saturating_sub(1);
|
||||||
|
let at_last = page.editor.current_field() >= last_idx;
|
||||||
|
if at_last && matches!(ma, MovementAction::Down | MovementAction::Next) {
|
||||||
|
page.state.last_canvas_field = last_idx;
|
||||||
|
page.set_current_focus(AddTableFocus::AddColumnButton);
|
||||||
|
app_state.ui.focus_outside_canvas = true;
|
||||||
|
return Ok(EventOutcome::Ok("Moved to Add button".to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let the FormEditor handle typing
|
||||||
match page.editor.handle_key_event(key_event) {
|
match page.editor.handle_key_event(key_event) {
|
||||||
canvas::keymap::KeyEventOutcome::Consumed(Some(msg)) => {
|
canvas::keymap::KeyEventOutcome::Consumed(Some(msg)) => {
|
||||||
page.sync_from_editor();
|
page.sync_from_editor();
|
||||||
@@ -61,8 +94,19 @@ pub fn handle_add_table_event(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Movement outside canvas
|
// 2) Outside canvas
|
||||||
if let Some(ma) = movement {
|
if let Some(ma) = movement {
|
||||||
|
// First let the AddTable state's own movement handler process
|
||||||
|
if page.state.handle_movement(ma) {
|
||||||
|
app_state.ui.focus_outside_canvas = !matches!(
|
||||||
|
page.current_focus(),
|
||||||
|
AddTableFocus::InputTableName
|
||||||
|
| AddTableFocus::InputColumnName
|
||||||
|
| AddTableFocus::InputColumnType
|
||||||
|
);
|
||||||
|
return Ok(EventOutcome::Ok(String::new()));
|
||||||
|
}
|
||||||
|
|
||||||
let mut current = page.current_focus();
|
let mut current = page.current_focus();
|
||||||
if move_focus(&ADD_TABLE_FOCUS_ORDER, &mut current, ma) {
|
if move_focus(&ADD_TABLE_FOCUS_ORDER, &mut current, ma) {
|
||||||
page.set_current_focus(current);
|
page.set_current_focus(current);
|
||||||
@@ -80,10 +124,7 @@ pub fn handle_add_table_event(
|
|||||||
MovementAction::Select => match page.current_focus() {
|
MovementAction::Select => match page.current_focus() {
|
||||||
AddTableFocus::AddColumnButton => {
|
AddTableFocus::AddColumnButton => {
|
||||||
if let Some(focus_after_add) =
|
if let Some(focus_after_add) =
|
||||||
crate::pages::admin_panel::add_table::logic::handle_add_column_action(
|
handle_add_column_action(&mut page.state, &mut String::new())
|
||||||
&mut page.state,
|
|
||||||
&mut String::new(),
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
page.set_current_focus(focus_after_add);
|
page.set_current_focus(focus_after_add);
|
||||||
return Ok(EventOutcome::Ok("Column added".into()));
|
return Ok(EventOutcome::Ok("Column added".into()));
|
||||||
@@ -100,25 +141,17 @@ pub fn handle_add_table_event(
|
|||||||
let state_clone = page.state.clone();
|
let state_clone = page.state.clone();
|
||||||
let sender_clone = save_result_sender.clone();
|
let sender_clone = save_result_sender.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let result =
|
let result = handle_save_table_action(&mut grpc_client, &state_clone).await;
|
||||||
crate::pages::admin_panel::add_table::logic::handle_save_table_action(
|
|
||||||
&mut grpc_client,
|
|
||||||
&state_clone,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
let _ = sender_clone.send(result).await;
|
let _ = sender_clone.send(result).await;
|
||||||
});
|
});
|
||||||
return Ok(EventOutcome::Ok("Saving table...".into()));
|
return Ok(EventOutcome::Ok("Saving table...".into()));
|
||||||
}
|
}
|
||||||
AddTableFocus::DeleteSelectedButton => {
|
AddTableFocus::DeleteSelectedButton => {
|
||||||
let msg =
|
let msg = handle_delete_selected_columns(&mut page.state);
|
||||||
crate::pages::admin_panel::add_table::logic::handle_delete_selected_columns(
|
|
||||||
&mut page.state,
|
|
||||||
);
|
|
||||||
return Ok(EventOutcome::Ok(msg));
|
return Ok(EventOutcome::Ok(msg));
|
||||||
}
|
}
|
||||||
AddTableFocus::CancelButton => {
|
AddTableFocus::CancelButton => {
|
||||||
return Ok(EventOutcome::Ok("Cancelled Add Table".into()));
|
return Ok(EventOutcome::Ok("Cancelled Add Table".to_string()));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -426,14 +426,14 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
router.navigate(Page::Admin(admin_state.clone()));
|
router.navigate(Page::Admin(admin_state.clone()));
|
||||||
}
|
}
|
||||||
AppView::AddTable => {
|
AppView::AddTable => {
|
||||||
router.navigate(Page::AddTable(
|
if let Page::AddTable(_) = &router.current {
|
||||||
|
} else {
|
||||||
|
let mut page =
|
||||||
add_table::state::AddTableFormState::from_state(
|
add_table::state::AddTableFormState::from_state(
|
||||||
admin_state.add_table_state.clone(),
|
admin_state.add_table_state.clone(),
|
||||||
),
|
);
|
||||||
));
|
|
||||||
if let Page::AddTable(page) = &mut router.current {
|
|
||||||
// Ensure keymap is set once
|
|
||||||
page.editor.set_keymap(config.build_canvas_keymap());
|
page.editor.set_keymap(config.build_canvas_keymap());
|
||||||
|
router.navigate(Page::AddTable(page));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AppView::AddLogic => {
|
AppView::AddLogic => {
|
||||||
|
|||||||
Reference in New Issue
Block a user