router2, needs bug fixes
This commit is contained in:
@@ -11,7 +11,8 @@ use tokio::sync::mpsc;
|
||||
use anyhow::Result;
|
||||
use crate::components::common::text_editor::TextEditor;
|
||||
use crate::services::ui_service::UiService;
|
||||
use tui_textarea::CursorMove; // Ensure this import is present
|
||||
use tui_textarea::CursorMove;
|
||||
use crate::pages::routing::{Router, Page};
|
||||
|
||||
pub type SaveLogicResultSender = mpsc::Sender<Result<String>>;
|
||||
|
||||
@@ -25,6 +26,7 @@ pub fn handle_add_logic_navigation(
|
||||
grpc_client: GrpcClient,
|
||||
_save_logic_sender: SaveLogicResultSender, // Marked as unused
|
||||
command_message: &mut String,
|
||||
router: &mut Router,
|
||||
) -> bool {
|
||||
// === FULLSCREEN SCRIPT EDITING - COMPLETE ISOLATION ===
|
||||
if add_logic_state.current_focus == AddLogicFocus::InsideScriptContent {
|
||||
@@ -380,7 +382,7 @@ pub fn handle_add_logic_navigation(
|
||||
}
|
||||
AddLogicFocus::CancelButton => {
|
||||
buffer_state.update_history(AppView::Admin);
|
||||
app_state.ui.show_add_logic = false;
|
||||
router.navigate(Page::Admin(app_state.admin_state().clone()));
|
||||
*command_message = "Cancelled Add Logic".to_string();
|
||||
*is_edit_mode = false;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/modes/canvas/common_mode.rs
|
||||
|
||||
use crate::tui::terminal::core::TerminalCore;
|
||||
use crate::state::pages::{form::FormState, auth::LoginState, auth::RegisterState, auth::AuthState};
|
||||
use crate::state::pages::auth::AuthState;
|
||||
use crate::state::app::state::AppState;
|
||||
use crate::services::grpc_client::GrpcClient;
|
||||
use crate::services::auth::AuthClient;
|
||||
@@ -13,74 +13,83 @@ use crate::tui::functions::common::{
|
||||
login::{save as login_save, revert as login_revert},
|
||||
register::{revert as register_revert},
|
||||
};
|
||||
use crate::pages::routing::{Router, Page};
|
||||
|
||||
pub async fn handle_core_action(
|
||||
action: &str,
|
||||
form_state: &mut FormState,
|
||||
auth_state: &mut AuthState,
|
||||
login_state: &mut LoginState,
|
||||
register_state: &mut RegisterState,
|
||||
grpc_client: &mut GrpcClient,
|
||||
auth_client: &mut AuthClient,
|
||||
terminal: &mut TerminalCore,
|
||||
app_state: &mut AppState,
|
||||
router: &mut Router,
|
||||
) -> Result<EventOutcome> {
|
||||
match action {
|
||||
"save" => {
|
||||
if app_state.ui.show_login {
|
||||
let message = login_save(auth_state, login_state, auth_client, app_state).await.context("Login save action failed")?;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
} else {
|
||||
let save_outcome = form_save(
|
||||
app_state,
|
||||
form_state,
|
||||
grpc_client,
|
||||
).await.context("Register save action failed")?;
|
||||
let message = match save_outcome {
|
||||
SaveOutcome::NoChange => "No changes to save.".to_string(),
|
||||
SaveOutcome::UpdatedExisting => "Entry updated.".to_string(),
|
||||
SaveOutcome::CreatedNew(_) => "New entry created.".to_string(),
|
||||
};
|
||||
Ok(EventOutcome::DataSaved(save_outcome, message))
|
||||
match &mut router.current {
|
||||
Page::Login(state) => {
|
||||
let message = login_save(auth_state, state, auth_client, app_state)
|
||||
.await
|
||||
.context("Login save action failed")?;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
}
|
||||
Page::Form(form_state) => {
|
||||
let save_outcome = form_save(app_state, form_state, grpc_client)
|
||||
.await
|
||||
.context("Form save action failed")?;
|
||||
let message = match save_outcome {
|
||||
SaveOutcome::NoChange => "No changes to save.".to_string(),
|
||||
SaveOutcome::UpdatedExisting => "Entry updated.".to_string(),
|
||||
SaveOutcome::CreatedNew(_) => "New entry created.".to_string(),
|
||||
};
|
||||
Ok(EventOutcome::DataSaved(save_outcome, message))
|
||||
}
|
||||
_ => Ok(EventOutcome::Ok("Save not applicable".into())),
|
||||
}
|
||||
},
|
||||
}
|
||||
"force_quit" => {
|
||||
terminal.cleanup()?;
|
||||
Ok(EventOutcome::Exit("Force exiting without saving.".to_string()))
|
||||
},
|
||||
}
|
||||
"save_and_quit" => {
|
||||
let message = if app_state.ui.show_login {
|
||||
login_save(auth_state, login_state, auth_client, app_state).await.context("Login save n quit action failed")?
|
||||
} else {
|
||||
let save_outcome = form_save(
|
||||
app_state,
|
||||
form_state,
|
||||
grpc_client,
|
||||
).await?;
|
||||
match save_outcome {
|
||||
SaveOutcome::NoChange => "No changes to save.".to_string(),
|
||||
SaveOutcome::UpdatedExisting => "Entry updated.".to_string(),
|
||||
SaveOutcome::CreatedNew(_) => "New entry created.".to_string(),
|
||||
let message = match &mut router.current {
|
||||
Page::Login(state) => {
|
||||
login_save(auth_state, state, auth_client, app_state)
|
||||
.await
|
||||
.context("Login save and quit action failed")?
|
||||
}
|
||||
Page::Form(form_state) => {
|
||||
let save_outcome = form_save(app_state, form_state, grpc_client).await?;
|
||||
match save_outcome {
|
||||
SaveOutcome::NoChange => "No changes to save.".to_string(),
|
||||
SaveOutcome::UpdatedExisting => "Entry updated.".to_string(),
|
||||
SaveOutcome::CreatedNew(_) => "New entry created.".to_string(),
|
||||
}
|
||||
}
|
||||
_ => "Save not applicable".to_string(),
|
||||
};
|
||||
terminal.cleanup()?;
|
||||
Ok(EventOutcome::Exit(format!("{}. Exiting application.", message)))
|
||||
},
|
||||
}
|
||||
"revert" => {
|
||||
if app_state.ui.show_login {
|
||||
let message = login_revert(login_state, app_state).await;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
} else if app_state.ui.show_register {
|
||||
let message = register_revert(register_state, app_state).await;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
} else {
|
||||
let message = form_revert(
|
||||
form_state,
|
||||
grpc_client,
|
||||
).await.context("Form revert x action failed")?;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
match &mut router.current {
|
||||
Page::Login(state) => {
|
||||
let message = login_revert(state, app_state).await;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
}
|
||||
Page::Register(state) => {
|
||||
let message = register_revert(state, app_state).await;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
}
|
||||
Page::Form(form_state) => {
|
||||
let message = form_revert(form_state, grpc_client)
|
||||
.await
|
||||
.context("Form revert action failed")?;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
}
|
||||
_ => Ok(EventOutcome::Ok("Revert not applicable".into())),
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => Ok(EventOutcome::Ok(format!("Core action not handled: {}", action))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/modes/common/commands.rs
|
||||
use crate::tui::terminal::core::TerminalCore;
|
||||
use crate::state::app::state::AppState;
|
||||
use crate::state::pages::{auth::LoginState, auth::RegisterState};
|
||||
use crate::pages::routing::{Router, Page};
|
||||
use anyhow::Result;
|
||||
|
||||
pub struct CommandHandler;
|
||||
@@ -16,11 +16,10 @@ impl CommandHandler {
|
||||
action: &str,
|
||||
terminal: &mut TerminalCore,
|
||||
app_state: &mut AppState,
|
||||
login_state: &LoginState,
|
||||
register_state: &RegisterState,
|
||||
router: &Router,
|
||||
) -> Result<(bool, String)> {
|
||||
match action {
|
||||
"quit" => self.handle_quit(terminal, app_state, login_state, register_state).await,
|
||||
"quit" => self.handle_quit(terminal, app_state, router).await,
|
||||
"force_quit" => self.handle_force_quit(terminal).await,
|
||||
"save_and_quit" => self.handle_save_quit(terminal).await,
|
||||
_ => Ok((false, format!("Unknown command: {}", action))),
|
||||
@@ -31,18 +30,14 @@ impl CommandHandler {
|
||||
&self,
|
||||
terminal: &mut TerminalCore,
|
||||
app_state: &mut AppState,
|
||||
login_state: &LoginState,
|
||||
register_state: &RegisterState,
|
||||
router: &Router,
|
||||
) -> Result<(bool, String)> {
|
||||
// Use actual unsaved changes state instead of is_saved flag
|
||||
let has_unsaved = if app_state.ui.show_login {
|
||||
login_state.has_unsaved_changes()
|
||||
} else if app_state.ui.show_register {
|
||||
register_state.has_unsaved_changes()
|
||||
} else if let Some(fs) = app_state.form_state_mut() {
|
||||
fs.has_unsaved_changes
|
||||
} else {
|
||||
false
|
||||
// Use router to check unsaved changes
|
||||
let has_unsaved = match &router.current {
|
||||
Page::Login(state) => state.has_unsaved_changes(),
|
||||
Page::Register(state) => state.has_unsaved_changes(),
|
||||
Page::Form(fs) => fs.has_unsaved_changes,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !has_unsaved {
|
||||
|
||||
@@ -30,6 +30,7 @@ use crate::state::{
|
||||
intro::IntroState,
|
||||
},
|
||||
};
|
||||
use crate::pages::routing::{Router, Page};
|
||||
use crate::search::state::SearchState;
|
||||
use crate::tui::functions::common::login::LoginResult;
|
||||
use crate::tui::functions::common::register::RegisterResult;
|
||||
@@ -127,90 +128,69 @@ impl EventHandler {
|
||||
|
||||
// Helper functions - replace the removed event_helper functions
|
||||
fn get_current_field_for_state(
|
||||
app_state: &AppState,
|
||||
login_state: &LoginState,
|
||||
register_state: &RegisterState,
|
||||
form_state: &FormState,
|
||||
router: &Router,
|
||||
) -> usize {
|
||||
if app_state.ui.show_login {
|
||||
login_state.current_field()
|
||||
} else if app_state.ui.show_register {
|
||||
register_state.current_field()
|
||||
} else {
|
||||
form_state.current_field()
|
||||
match &router.current {
|
||||
Page::Login(state) => state.current_field(),
|
||||
Page::Register(state) => state.current_field(),
|
||||
Page::Form(state) => state.current_field(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_current_cursor_pos_for_state(
|
||||
app_state: &AppState,
|
||||
login_state: &LoginState,
|
||||
register_state: &RegisterState,
|
||||
form_state: &FormState,
|
||||
router: &Router,
|
||||
) -> usize {
|
||||
if app_state.ui.show_login {
|
||||
login_state.current_cursor_pos()
|
||||
} else if app_state.ui.show_register {
|
||||
register_state.current_cursor_pos()
|
||||
} else {
|
||||
form_state.current_cursor_pos()
|
||||
match &router.current {
|
||||
Page::Login(state) => state.current_cursor_pos(),
|
||||
Page::Register(state) => state.current_cursor_pos(),
|
||||
Page::Form(state) => state.current_cursor_pos(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_has_unsaved_changes_for_state(
|
||||
app_state: &AppState,
|
||||
login_state: &LoginState,
|
||||
register_state: &RegisterState,
|
||||
form_state: &FormState,
|
||||
router: &Router,
|
||||
) -> bool {
|
||||
if app_state.ui.show_login {
|
||||
login_state.has_unsaved_changes()
|
||||
} else if app_state.ui.show_register {
|
||||
register_state.has_unsaved_changes()
|
||||
} else {
|
||||
form_state.has_unsaved_changes()
|
||||
match &router.current {
|
||||
Page::Login(state) => state.has_unsaved_changes(),
|
||||
Page::Register(state) => state.has_unsaved_changes(),
|
||||
Page::Form(state) => state.has_unsaved_changes(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_current_input_for_state<'a>(
|
||||
app_state: &AppState,
|
||||
login_state: &'a LoginState,
|
||||
register_state: &'a RegisterState,
|
||||
form_state: &'a FormState,
|
||||
router: &'a Router,
|
||||
) -> &'a str {
|
||||
if app_state.ui.show_login {
|
||||
login_state.get_current_input()
|
||||
} else if app_state.ui.show_register {
|
||||
register_state.get_current_input()
|
||||
} else {
|
||||
form_state.get_current_input()
|
||||
match &router.current {
|
||||
Page::Login(state) => state.get_current_input(),
|
||||
Page::Register(state) => state.get_current_input(),
|
||||
Page::Form(state) => state.get_current_input(),
|
||||
_ => "",
|
||||
}
|
||||
}
|
||||
|
||||
fn set_current_cursor_pos_for_state(
|
||||
app_state: &AppState,
|
||||
login_state: &mut LoginState,
|
||||
register_state: &mut RegisterState,
|
||||
form_state: &mut FormState,
|
||||
router: &mut Router,
|
||||
pos: usize,
|
||||
) {
|
||||
if app_state.ui.show_login {
|
||||
login_state.set_current_cursor_pos(pos);
|
||||
} else if app_state.ui.show_register {
|
||||
register_state.set_current_cursor_pos(pos);
|
||||
} else {
|
||||
form_state.set_current_cursor_pos(pos);
|
||||
match &mut router.current {
|
||||
Page::Login(state) => state.set_current_cursor_pos(pos),
|
||||
Page::Register(state) => state.set_current_cursor_pos(pos),
|
||||
Page::Form(state) => state.set_current_cursor_pos(pos),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cursor_pos_for_mixed_state(
|
||||
app_state: &AppState,
|
||||
login_state: &LoginState,
|
||||
form_state: &FormState,
|
||||
router: &Router,
|
||||
) -> usize {
|
||||
if app_state.ui.show_login || app_state.ui.show_register {
|
||||
login_state.current_cursor_pos()
|
||||
} else {
|
||||
form_state.current_cursor_pos()
|
||||
match &router.current {
|
||||
Page::Login(state) => state.current_cursor_pos(),
|
||||
Page::Register(state) => state.current_cursor_pos(),
|
||||
Page::Form(state) => state.current_cursor_pos(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,12 +202,9 @@ impl EventHandler {
|
||||
terminal: &mut TerminalCore,
|
||||
command_handler: &mut CommandHandler,
|
||||
auth_state: &mut AuthState,
|
||||
login_state: &mut LoginState,
|
||||
register_state: &mut RegisterState,
|
||||
intro_state: &mut IntroState,
|
||||
admin_state: &mut AdminState,
|
||||
buffer_state: &mut BufferState,
|
||||
app_state: &mut AppState,
|
||||
router: &mut Router,
|
||||
) -> Result<EventOutcome> {
|
||||
if app_state.ui.show_search_palette {
|
||||
if let Event::Key(key_event) = event {
|
||||
@@ -244,7 +221,7 @@ impl EventHandler {
|
||||
}
|
||||
|
||||
let mut current_mode =
|
||||
ModeManager::derive_mode(app_state, self, admin_state);
|
||||
ModeManager::derive_mode(app_state, self, router);
|
||||
|
||||
if current_mode == AppMode::General && self.navigation_state.active {
|
||||
if let Event::Key(key_event) = event {
|
||||
@@ -258,7 +235,7 @@ impl EventHandler {
|
||||
if !self.navigation_state.active {
|
||||
self.command_message = outcome.get_message_if_ok();
|
||||
current_mode =
|
||||
ModeManager::derive_mode(app_state, self, admin_state);
|
||||
ModeManager::derive_mode(app_state, self, router);
|
||||
}
|
||||
app_state.update_mode(current_mode);
|
||||
return Ok(outcome);
|
||||
@@ -269,25 +246,14 @@ impl EventHandler {
|
||||
|
||||
app_state.update_mode(current_mode);
|
||||
|
||||
let current_view = {
|
||||
let ui = &app_state.ui;
|
||||
if ui.show_intro {
|
||||
AppView::Intro
|
||||
} else if ui.show_login {
|
||||
AppView::Login
|
||||
} else if ui.show_register {
|
||||
AppView::Register
|
||||
} else if ui.show_admin {
|
||||
AppView::Admin
|
||||
} else if ui.show_add_logic {
|
||||
AppView::AddLogic
|
||||
} else if ui.show_add_table {
|
||||
AppView::AddTable
|
||||
} else if ui.show_form {
|
||||
AppView::Form
|
||||
} else {
|
||||
AppView::Scratch
|
||||
}
|
||||
let current_view = match &router.current {
|
||||
Page::Intro(_) => AppView::Intro,
|
||||
Page::Login(_) => AppView::Login,
|
||||
Page::Register(_) => AppView::Register,
|
||||
Page::Admin(_) => AppView::Admin,
|
||||
Page::AddLogic(_) => AppView::AddLogic,
|
||||
Page::AddTable(_) => AppView::AddTable,
|
||||
Page::Form(_) => AppView::Form,
|
||||
};
|
||||
buffer_state.update_history(current_view);
|
||||
|
||||
@@ -297,10 +263,8 @@ impl EventHandler {
|
||||
&Event::Key(key_event),
|
||||
config,
|
||||
app_state,
|
||||
login_state,
|
||||
register_state,
|
||||
buffer_state,
|
||||
admin_state,
|
||||
router,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -386,7 +350,7 @@ impl EventHandler {
|
||||
config.get_general_action(key_code, modifiers)
|
||||
{
|
||||
if action == "open_search" {
|
||||
if app_state.ui.show_form {
|
||||
if let Page::Form(_) = &router.current {
|
||||
if let Some(table_name) =
|
||||
app_state.current_view_table_name.clone()
|
||||
{
|
||||
@@ -405,31 +369,31 @@ impl EventHandler {
|
||||
|
||||
match current_mode {
|
||||
AppMode::General => {
|
||||
if app_state.ui.show_admin
|
||||
&& auth_state.role.as_deref() == Some("admin")
|
||||
{
|
||||
if admin_nav::handle_admin_navigation(
|
||||
key_event,
|
||||
config,
|
||||
app_state,
|
||||
admin_state,
|
||||
buffer_state,
|
||||
&mut self.command_message,
|
||||
) {
|
||||
return Ok(EventOutcome::Ok(
|
||||
self.command_message.clone(),
|
||||
));
|
||||
if let Page::Admin(admin_state) = &router.current {
|
||||
if auth_state.role.as_deref() == Some("admin") {
|
||||
if admin_nav::handle_admin_navigation(
|
||||
key_event,
|
||||
config,
|
||||
app_state,
|
||||
admin_state,
|
||||
buffer_state,
|
||||
&mut self.command_message,
|
||||
) {
|
||||
return Ok(EventOutcome::Ok(
|
||||
self.command_message.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if app_state.ui.show_add_logic {
|
||||
if let Page::AddLogic(add_logic_state) = &mut router.current {
|
||||
let client_clone = self.grpc_client.clone();
|
||||
let sender_clone = self.save_logic_result_sender.clone();
|
||||
if add_logic_nav::handle_add_logic_navigation(
|
||||
key_event,
|
||||
config,
|
||||
app_state,
|
||||
&mut admin_state.add_logic_state,
|
||||
add_logic_state,
|
||||
&mut self.is_edit_mode,
|
||||
buffer_state,
|
||||
client_clone,
|
||||
@@ -442,14 +406,14 @@ impl EventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if app_state.ui.show_add_table {
|
||||
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(
|
||||
key_event,
|
||||
config,
|
||||
app_state,
|
||||
&mut admin_state.add_table_state,
|
||||
add_table_state,
|
||||
client_clone,
|
||||
sender_clone,
|
||||
&mut self.command_message,
|
||||
@@ -464,10 +428,7 @@ impl EventHandler {
|
||||
key_event,
|
||||
config,
|
||||
app_state,
|
||||
login_state,
|
||||
register_state,
|
||||
intro_state,
|
||||
admin_state,
|
||||
router,
|
||||
&mut self.command_mode,
|
||||
&mut self.command_input,
|
||||
&mut self.command_message,
|
||||
@@ -482,53 +443,68 @@ impl EventHandler {
|
||||
buffer_state,
|
||||
index,
|
||||
);
|
||||
if app_state.ui.show_admin
|
||||
&& !app_state
|
||||
if let Page::Admin(admin_state) = &router.current {
|
||||
if !app_state
|
||||
.profile_tree
|
||||
.profiles
|
||||
.is_empty()
|
||||
{
|
||||
admin_state
|
||||
.profile_list_state
|
||||
.select(Some(0));
|
||||
{
|
||||
admin_state
|
||||
.profile_list_state
|
||||
.select(Some(0));
|
||||
}
|
||||
}
|
||||
format!("Intro Option {} selected", index)
|
||||
}
|
||||
UiContext::Login => match index {
|
||||
0 => login::initiate_login(
|
||||
login_state,
|
||||
app_state,
|
||||
self.auth_client.clone(),
|
||||
self.login_result_sender.clone(),
|
||||
),
|
||||
1 => login::back_to_main(
|
||||
login_state,
|
||||
app_state,
|
||||
buffer_state,
|
||||
)
|
||||
.await,
|
||||
_ => "Invalid Login Option".to_string(),
|
||||
},
|
||||
UiContext::Register => match index {
|
||||
0 => register::initiate_registration(
|
||||
register_state,
|
||||
app_state,
|
||||
self.auth_client.clone(),
|
||||
self.register_result_sender.clone(),
|
||||
),
|
||||
1 => register::back_to_login(
|
||||
register_state,
|
||||
app_state,
|
||||
buffer_state,
|
||||
)
|
||||
.await,
|
||||
_ => "Invalid Login Option".to_string(),
|
||||
},
|
||||
UiContext::Login => {
|
||||
if let Page::Login(login_state) = &router.current {
|
||||
match index {
|
||||
0 => login::initiate_login(
|
||||
login_state,
|
||||
app_state,
|
||||
self.auth_client.clone(),
|
||||
self.login_result_sender.clone(),
|
||||
),
|
||||
1 => login::back_to_main(
|
||||
login_state,
|
||||
app_state,
|
||||
buffer_state,
|
||||
)
|
||||
.await,
|
||||
_ => "Invalid Login Option".to_string(),
|
||||
}
|
||||
} else {
|
||||
"Invalid state".to_string()
|
||||
}
|
||||
}
|
||||
UiContext::Register => {
|
||||
if let Page::Register(register_state) = &router.current {
|
||||
match index {
|
||||
0 => register::initiate_registration(
|
||||
register_state,
|
||||
app_state,
|
||||
self.auth_client.clone(),
|
||||
self.register_result_sender.clone(),
|
||||
),
|
||||
1 => register::back_to_login(
|
||||
register_state,
|
||||
app_state,
|
||||
buffer_state,
|
||||
)
|
||||
.await,
|
||||
_ => "Invalid Login Option".to_string(),
|
||||
}
|
||||
} else {
|
||||
"Invalid state".to_string()
|
||||
}
|
||||
}
|
||||
UiContext::Admin => {
|
||||
admin::handle_admin_selection(
|
||||
app_state,
|
||||
admin_state,
|
||||
);
|
||||
if let Page::Admin(admin_state) = &router.current {
|
||||
admin::handle_admin_selection(
|
||||
app_state,
|
||||
admin_state,
|
||||
);
|
||||
}
|
||||
format!("Admin Option {} selected", index)
|
||||
}
|
||||
UiContext::Dialog => "Internal error: Unexpected dialog state"
|
||||
@@ -542,7 +518,7 @@ impl EventHandler {
|
||||
|
||||
AppMode::ReadOnly => {
|
||||
// First let the canvas editor try to handle the key
|
||||
if app_state.ui.show_form {
|
||||
if let Page::Form(_) = &router.current {
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
let outcome = editor.handle_key_event(key_event);
|
||||
let new_mode = AppMode::from(editor.mode());
|
||||
@@ -588,10 +564,9 @@ impl EventHandler {
|
||||
.handle_core_action(
|
||||
action,
|
||||
auth_state,
|
||||
login_state,
|
||||
register_state,
|
||||
terminal,
|
||||
app_state,
|
||||
router,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -603,7 +578,7 @@ impl EventHandler {
|
||||
}
|
||||
|
||||
AppMode::Highlight => {
|
||||
if app_state.ui.show_form {
|
||||
if let Page::Form(_) = &router.current {
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
let outcome = editor.handle_key_event(key_event);
|
||||
let new_mode = AppMode::from(editor.mode());
|
||||
@@ -640,10 +615,9 @@ impl EventHandler {
|
||||
.handle_core_action(
|
||||
action,
|
||||
auth_state,
|
||||
login_state,
|
||||
register_state,
|
||||
terminal,
|
||||
app_state,
|
||||
router,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -652,7 +626,7 @@ impl EventHandler {
|
||||
}
|
||||
|
||||
// Let the canvas editor handle edit-mode keys
|
||||
if app_state.ui.show_form {
|
||||
if let Page::Form(_) = &router.current {
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
let outcome = editor.handle_key_event(key_event);
|
||||
let new_mode = AppMode::from(editor.mode());
|
||||
@@ -696,7 +670,7 @@ impl EventHandler {
|
||||
}
|
||||
|
||||
if config.is_command_execute(key_code, modifiers) {
|
||||
let (mut current_position, total_count) = if let Some(fs) = app_state.form_state() {
|
||||
let (mut current_position, total_count) = if let Page::Form(fs) = &router.current {
|
||||
(fs.current_position, fs.total_count)
|
||||
} else {
|
||||
(1, 0)
|
||||
@@ -706,8 +680,7 @@ impl EventHandler {
|
||||
key_event,
|
||||
config,
|
||||
app_state,
|
||||
login_state,
|
||||
register_state,
|
||||
router,
|
||||
&mut self.command_input,
|
||||
&mut self.command_message,
|
||||
&mut self.grpc_client,
|
||||
@@ -716,7 +689,7 @@ impl EventHandler {
|
||||
&mut current_position,
|
||||
total_count,
|
||||
).await?;
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
if let Page::Form(fs) = &mut router.current {
|
||||
fs.current_position = current_position;
|
||||
}
|
||||
self.command_mode = false;
|
||||
@@ -724,7 +697,7 @@ impl EventHandler {
|
||||
let new_mode = ModeManager::derive_mode(
|
||||
app_state,
|
||||
self,
|
||||
admin_state,
|
||||
router,
|
||||
);
|
||||
app_state.update_mode(new_mode);
|
||||
return Ok(outcome);
|
||||
@@ -746,9 +719,7 @@ impl EventHandler {
|
||||
&sequence,
|
||||
) == Some("find_file_palette_toggle")
|
||||
{
|
||||
if app_state.ui.show_form
|
||||
|| app_state.ui.show_intro
|
||||
{
|
||||
if matches!(&router.current, Page::Form(_) | Page::Intro(_)) {
|
||||
let mut all_table_paths: Vec<String> =
|
||||
app_state
|
||||
.profile_tree
|
||||
@@ -830,14 +801,13 @@ impl EventHandler {
|
||||
&mut self,
|
||||
action: &str,
|
||||
auth_state: &mut AuthState,
|
||||
login_state: &mut LoginState,
|
||||
register_state: &mut RegisterState,
|
||||
terminal: &mut TerminalCore,
|
||||
app_state: &mut AppState,
|
||||
router: &mut Router,
|
||||
) -> Result<EventOutcome> {
|
||||
match action {
|
||||
"save" => {
|
||||
if app_state.ui.show_login {
|
||||
if let Page::Login(login_state) = &router.current {
|
||||
let message = crate::tui::functions::common::login::save(
|
||||
auth_state,
|
||||
login_state,
|
||||
@@ -847,7 +817,7 @@ impl EventHandler {
|
||||
.await?;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
} else {
|
||||
let save_outcome = if let Some(fs) = app_state.form_state_mut() {
|
||||
let save_outcome = if let Page::Form(_) = &router.current {
|
||||
crate::tui::functions::common::form::save(
|
||||
app_state,
|
||||
&mut self.grpc_client,
|
||||
@@ -874,7 +844,7 @@ impl EventHandler {
|
||||
))
|
||||
}
|
||||
"save_and_quit" => {
|
||||
let message = if app_state.ui.show_login {
|
||||
let message = if let Page::Login(login_state) = &router.current {
|
||||
crate::tui::functions::common::login::save(
|
||||
auth_state,
|
||||
login_state,
|
||||
@@ -903,17 +873,17 @@ impl EventHandler {
|
||||
)))
|
||||
}
|
||||
"revert" => {
|
||||
let message = if app_state.ui.show_login {
|
||||
let message = if let Page::Login(login_state) = &router.current {
|
||||
crate::tui::functions::common::login::revert(login_state, app_state)
|
||||
.await
|
||||
} else if app_state.ui.show_register {
|
||||
} else if let Page::Register(register_state) = &router.current {
|
||||
crate::tui::functions::common::register::revert(
|
||||
register_state,
|
||||
app_state,
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
if let Page::Form(_) = &router.current {
|
||||
crate::tui::functions::common::form::revert(
|
||||
app_state,
|
||||
&mut self.grpc_client,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use crate::state::app::state::AppState;
|
||||
use crate::modes::handlers::event::EventHandler;
|
||||
use crate::state::pages::add_logic::AddLogicFocus;
|
||||
use crate::state::pages::admin::AdminState;
|
||||
use crate::pages::routing::{Router, Page};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AppMode {
|
||||
@@ -28,11 +28,11 @@ impl From<canvas::AppMode> for AppMode {
|
||||
pub struct ModeManager;
|
||||
|
||||
impl ModeManager {
|
||||
/// Determine current mode based on app state
|
||||
/// Determine current mode based on app state + router
|
||||
pub fn derive_mode(
|
||||
app_state: &AppState,
|
||||
event_handler: &EventHandler,
|
||||
admin_state: &AdminState,
|
||||
router: &Router,
|
||||
) -> AppMode {
|
||||
// Navigation palette always forces General
|
||||
if event_handler.navigation_state.active {
|
||||
@@ -44,16 +44,17 @@ impl ModeManager {
|
||||
return AppMode::Command;
|
||||
}
|
||||
|
||||
// Always trust the FormEditor when a form is active
|
||||
if app_state.ui.show_form && !app_state.ui.focus_outside_canvas {
|
||||
if let Some(editor) = &app_state.form_editor {
|
||||
return AppMode::from(editor.mode());
|
||||
match &router.current {
|
||||
// --- Form view ---
|
||||
Page::Form(_) if !app_state.ui.focus_outside_canvas => {
|
||||
if let Some(editor) = &app_state.form_editor {
|
||||
return AppMode::from(editor.mode());
|
||||
}
|
||||
AppMode::General
|
||||
}
|
||||
}
|
||||
|
||||
// --- Non-form views (add_logic, add_table, etc.) ---
|
||||
if app_state.ui.show_add_logic {
|
||||
match admin_state.add_logic_state.current_focus {
|
||||
// --- AddLogic view ---
|
||||
Page::AddLogic(state) => match state.current_focus {
|
||||
AddLogicFocus::InputLogicName
|
||||
| AddLogicFocus::InputTargetColumn
|
||||
| AddLogicFocus::InputDescription => {
|
||||
@@ -64,26 +65,30 @@ impl ModeManager {
|
||||
}
|
||||
}
|
||||
_ => AppMode::General,
|
||||
},
|
||||
|
||||
// --- AddTable view ---
|
||||
Page::AddTable(_) => {
|
||||
if app_state.ui.focus_outside_canvas {
|
||||
AppMode::General
|
||||
} else if event_handler.is_edit_mode {
|
||||
AppMode::Edit
|
||||
} else {
|
||||
AppMode::ReadOnly
|
||||
}
|
||||
}
|
||||
} else if app_state.ui.show_add_table {
|
||||
if app_state.ui.focus_outside_canvas {
|
||||
AppMode::General
|
||||
} else if event_handler.is_edit_mode {
|
||||
AppMode::Edit
|
||||
} else {
|
||||
AppMode::ReadOnly
|
||||
|
||||
// --- Login/Register views ---
|
||||
Page::Login(_) | Page::Register(_) => {
|
||||
if event_handler.is_edit_mode {
|
||||
AppMode::Edit
|
||||
} else {
|
||||
AppMode::ReadOnly
|
||||
}
|
||||
}
|
||||
} else if app_state.ui.show_login
|
||||
|| app_state.ui.show_register
|
||||
{
|
||||
// login/register still use the old flag
|
||||
if event_handler.is_edit_mode {
|
||||
AppMode::Edit
|
||||
} else {
|
||||
AppMode::ReadOnly
|
||||
}
|
||||
} else {
|
||||
AppMode::General
|
||||
|
||||
// --- Everything else (Intro, Admin, etc.) ---
|
||||
_ => AppMode::General,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,11 @@ use crate::components::{
|
||||
intro::intro::render_intro,
|
||||
render_background,
|
||||
};
|
||||
use crate::bottom_panel::{command_line::render_command_line, status_line::render_status_line, find_file_palette};
|
||||
use crate::bottom_panel::{
|
||||
command_line::render_command_line,
|
||||
status_line::render_status_line,
|
||||
find_file_palette,
|
||||
};
|
||||
use crate::sidebar::{calculate_sidebar_layout, render_sidebar};
|
||||
use crate::buffer::render_buffer_list;
|
||||
use crate::search::render_search_palette;
|
||||
@@ -16,12 +20,7 @@ use crate::config::colors::themes::Theme;
|
||||
use crate::modes::general::command_navigation::NavigationState;
|
||||
use crate::buffer::state::BufferState;
|
||||
use crate::state::app::state::AppState;
|
||||
use crate::state::pages::admin::AdminState;
|
||||
use crate::state::pages::auth::AuthState;
|
||||
use crate::state::pages::auth::LoginState;
|
||||
use crate::state::pages::auth::RegisterState;
|
||||
use crate::state::pages::form::FormState;
|
||||
use crate::state::pages::intro::IntroState;
|
||||
use crate::bottom_panel::layout::{bottom_panel_constraints, render_bottom_panel};
|
||||
use crate::components::render_form;
|
||||
use ratatui::{
|
||||
@@ -46,6 +45,7 @@ pub fn render_ui(
|
||||
) {
|
||||
render_background(f, f.area(), theme);
|
||||
|
||||
// Layout: optional buffer list + main content + bottom panel
|
||||
let mut main_layout_constraints = vec![Constraint::Min(1)];
|
||||
if app_state.ui.show_buffer_list {
|
||||
main_layout_constraints.insert(0, Constraint::Length(1));
|
||||
@@ -73,7 +73,7 @@ pub fn render_ui(
|
||||
let main_content_area = root_chunks[chunk_idx];
|
||||
chunk_idx += 1;
|
||||
|
||||
// ✅ Instead of checking app_state.ui.show_*, just match router.current
|
||||
// Page rendering is now fully router-driven
|
||||
match &mut router.current {
|
||||
Page::Intro(state) => render_intro(f, state, main_content_area, theme),
|
||||
Page::Login(state) => render_login(
|
||||
@@ -160,6 +160,7 @@ pub fn render_ui(
|
||||
}
|
||||
}
|
||||
|
||||
// Global overlays (not tied to a page)
|
||||
if let Some(area) = buffer_list_area {
|
||||
render_buffer_list(f, area, theme, buffer_state, app_state);
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ pub async fn run_ui() -> Result<()> {
|
||||
event_processed = true;
|
||||
|
||||
if let crossterm_event::Event::Key(key_event) = &event {
|
||||
if app_state.ui.show_form {
|
||||
if let Page::Form(_) = &router.current {
|
||||
if let Some(editor) = app_state.form_editor.as_mut() {
|
||||
match editor.handle_key_event(*key_event) {
|
||||
KeyEventOutcome::Consumed(Some(msg)) => {
|
||||
@@ -391,7 +391,7 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
if app_state.ui.show_form {
|
||||
if let Page::Form(_) = &router.current {
|
||||
let current_view_profile = app_state.current_view_profile_name.clone();
|
||||
let current_view_table = app_state.current_view_table_name.clone();
|
||||
|
||||
@@ -477,18 +477,21 @@ pub async fn run_ui() -> Result<()> {
|
||||
// Now we can use CanvasState methods like get_current_input(), current_field(), etc.
|
||||
|
||||
if let Some((profile_name, table_name)) = app_state.pending_table_structure_fetch.take() {
|
||||
if app_state.ui.show_add_logic {
|
||||
if admin_state.add_logic_state.profile_name == profile_name &&
|
||||
admin_state.add_logic_state.selected_table_name.as_deref() == Some(table_name.as_str()) {
|
||||
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(
|
||||
&mut grpc_client,
|
||||
&mut admin_state.add_logic_state,
|
||||
state,
|
||||
&app_state.profile_tree,
|
||||
).await.unwrap_or_else(|e| {
|
||||
error!("Error initializing add_logic_table_data: {}", e);
|
||||
format!("Error fetching table structure: {}", e)
|
||||
});
|
||||
)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
error!("Error initializing add_logic_table_data: {}", e);
|
||||
format!("Error fetching table structure: {}", e)
|
||||
});
|
||||
|
||||
if !fetch_message.contains("Error") && !fetch_message.contains("Warning") {
|
||||
info!("{}", fetch_message);
|
||||
@@ -498,10 +501,11 @@ pub async fn run_ui() -> Result<()> {
|
||||
needs_redraw = true;
|
||||
} else {
|
||||
error!(
|
||||
"Mismatch in pending_table_structure_fetch: app_state wants {}.{}, but add_logic_state is for {}.{:?}",
|
||||
profile_name, table_name,
|
||||
admin_state.add_logic_state.profile_name,
|
||||
admin_state.add_logic_state.selected_table_name
|
||||
"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 {
|
||||
@@ -512,21 +516,21 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(table_name) = admin_state.add_logic_state.script_editor_awaiting_column_autocomplete.clone() {
|
||||
if app_state.ui.show_add_logic {
|
||||
let profile_name = admin_state.add_logic_state.profile_name.clone();
|
||||
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) => {
|
||||
admin_state.add_logic_state.set_columns_for_table_autocomplete(columns.clone());
|
||||
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);
|
||||
admin_state.add_logic_state.script_editor_awaiting_column_autocomplete = None;
|
||||
admin_state.add_logic_state.deactivate_script_editor_autocomplete();
|
||||
state.script_editor_awaiting_column_autocomplete = None;
|
||||
state.deactivate_script_editor_autocomplete();
|
||||
event_handler.command_message = format!("Error loading columns for '{}': {}", table_name, e);
|
||||
}
|
||||
}
|
||||
@@ -540,59 +544,75 @@ pub async fn run_ui() -> Result<()> {
|
||||
let position_changed = current_position != position_before_event;
|
||||
let mut position_logic_needs_redraw = false;
|
||||
|
||||
if app_state.ui.show_form && !table_just_switched {
|
||||
if position_changed && !event_handler.is_edit_mode {
|
||||
position_logic_needs_redraw = true;
|
||||
if let Page::Form(form_state) = &mut router.current {
|
||||
if !table_just_switched {
|
||||
if position_changed && !event_handler.is_edit_mode {
|
||||
position_logic_needs_redraw = true;
|
||||
|
||||
if let Some(form_state) = app_state.form_state_mut() {
|
||||
if form_state.current_position > form_state.total_count {
|
||||
form_state.reset_to_empty();
|
||||
event_handler.command_message = format!("New entry for {}.{}", form_state.profile_name, form_state.table_name);
|
||||
} else {
|
||||
match UiService::load_table_data_by_position(&mut grpc_client, form_state).await {
|
||||
Ok(load_message) => {
|
||||
if event_handler.command_message.is_empty() || !load_message.starts_with("Error") {
|
||||
event_handler.command_message = load_message;
|
||||
if let Some(form_state) = app_state.form_state_mut() {
|
||||
if form_state.current_position > form_state.total_count {
|
||||
form_state.reset_to_empty();
|
||||
event_handler.command_message = format!(
|
||||
"New entry for {}.{}",
|
||||
form_state.profile_name,
|
||||
form_state.table_name
|
||||
);
|
||||
} else {
|
||||
match UiService::load_table_data_by_position(&mut grpc_client, form_state).await {
|
||||
Ok(load_message) => {
|
||||
if event_handler.command_message.is_empty()
|
||||
|| !load_message.starts_with("Error")
|
||||
{
|
||||
event_handler.command_message = load_message;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
event_handler.command_message =
|
||||
format!("Error loading data: {}", e);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
event_handler.command_message = format!("Error loading data: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let current_input_after_load_str = form_state.get_current_input();
|
||||
let current_input_len_after_load = current_input_after_load_str.chars().count();
|
||||
let max_cursor_pos = if current_input_len_after_load > 0 {
|
||||
current_input_len_after_load.saturating_sub(1)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
}
|
||||
} else if !position_changed && !event_handler.is_edit_mode {
|
||||
if let Some(form_state) = app_state.form_state_mut() {
|
||||
let current_input_str = form_state.get_current_input();
|
||||
let current_input_len = current_input_str.chars().count();
|
||||
let max_cursor_pos = if current_input_len > 0 {
|
||||
current_input_len.saturating_sub(1)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
let current_input_after_load_str = form_state.get_current_input();
|
||||
let current_input_len_after_load =
|
||||
current_input_after_load_str.chars().count();
|
||||
let max_cursor_pos = if current_input_len_after_load > 0 {
|
||||
current_input_len_after_load.saturating_sub(1)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
form_state.current_cursor_pos =
|
||||
event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
}
|
||||
} else if !position_changed && !event_handler.is_edit_mode {
|
||||
if let Some(form_state) = app_state.form_state_mut() {
|
||||
let current_input_str = form_state.get_current_input();
|
||||
let current_input_len = current_input_str.chars().count();
|
||||
let max_cursor_pos = if current_input_len > 0 {
|
||||
current_input_len.saturating_sub(1)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
form_state.current_cursor_pos =
|
||||
event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if app_state.ui.show_register {
|
||||
} else if let Page::Register(state) = &mut router.current {
|
||||
if !event_handler.is_edit_mode {
|
||||
let current_input = register_state.get_current_input();
|
||||
let max_cursor_pos = if !current_input.is_empty() { current_input.len() - 1 } else { 0 };
|
||||
register_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
let current_input = state.get_current_input();
|
||||
let max_cursor_pos =
|
||||
if !current_input.is_empty() { current_input.len() - 1 } else { 0 };
|
||||
state.current_cursor_pos =
|
||||
event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
}
|
||||
} else if app_state.ui.show_login {
|
||||
} else if let Page::Login(state) = &mut router.current {
|
||||
if !event_handler.is_edit_mode {
|
||||
let current_input = login_state.get_current_input();
|
||||
let max_cursor_pos = if !current_input.is_empty() { current_input.len() - 1 } else { 0 };
|
||||
login_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
let current_input = state.get_current_input();
|
||||
let max_cursor_pos =
|
||||
if !current_input.is_empty() { current_input.len() - 1 } else { 0 };
|
||||
state.current_cursor_pos =
|
||||
event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,7 +643,7 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
|
||||
if event_processed || needs_redraw || position_changed {
|
||||
let current_mode = ModeManager::derive_mode(&app_state, &event_handler, &admin_state);
|
||||
let current_mode = ModeManager::derive_mode(&app_state, &event_handler, &router);
|
||||
match current_mode {
|
||||
AppMode::Edit => { terminal.show_cursor()?; }
|
||||
AppMode::Highlight => { terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; terminal.show_cursor()?; }
|
||||
|
||||
Reference in New Issue
Block a user