event.rs and ui.rs refactor for the forms page(moved logic to the forms page dir and just calling it now)
This commit is contained in:
@@ -82,8 +82,6 @@ impl TableDependencyGraph {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ... (NavigationState struct and its new(), activate_*, deactivate(), add_char(), remove_char(), move_*, autocomplete_selected(), get_display_input() methods are unchanged) ...
|
|
||||||
pub struct NavigationState {
|
pub struct NavigationState {
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
pub input: String,
|
pub input: String,
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ use crate::pages::register::RegisterResult;
|
|||||||
use crate::pages::routing::{Router, Page};
|
use crate::pages::routing::{Router, Page};
|
||||||
use crate::movement::MovementAction;
|
use crate::movement::MovementAction;
|
||||||
use crate::dialog;
|
use crate::dialog;
|
||||||
|
use crate::pages::forms;
|
||||||
use crate::pages::forms::FormState;
|
use crate::pages::forms::FormState;
|
||||||
use crate::pages::forms::logic::{save, revert, SaveOutcome};
|
use crate::pages::forms::logic::{save, revert, SaveOutcome};
|
||||||
use crate::search::state::SearchState;
|
use crate::search::state::SearchState;
|
||||||
@@ -384,6 +385,14 @@ impl EventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if let Page::Form(path) = &router.current {
|
||||||
|
// NEW: Delegate Form event handling
|
||||||
|
return forms::event::handle_form_event(
|
||||||
|
event,
|
||||||
|
app_state,
|
||||||
|
path,
|
||||||
|
&mut self.ideal_cursor_column
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if toggle_sidebar(
|
if toggle_sidebar(
|
||||||
@@ -858,25 +867,14 @@ impl EventHandler {
|
|||||||
&mut self.auth_client,
|
&mut self.auth_client,
|
||||||
app_state,
|
app_state,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(EventOutcome::Ok(message))
|
Ok(EventOutcome::Ok(message))
|
||||||
} else {
|
} else {
|
||||||
let save_outcome = if let Page::Form(path) = &router.current {
|
if let Page::Form(path) = &router.current {
|
||||||
save(
|
forms::event::save_form(app_state, path, &mut self.grpc_client).await
|
||||||
app_state,
|
|
||||||
path,
|
|
||||||
&mut self.grpc_client,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
} else {
|
} else {
|
||||||
SaveOutcome::NoChange
|
Ok(EventOutcome::Ok("Nothing to save".to_string()))
|
||||||
};
|
}
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"force_quit" => {
|
"force_quit" => {
|
||||||
@@ -898,19 +896,18 @@ impl EventHandler {
|
|||||||
&mut self.auth_client,
|
&mut self.auth_client,
|
||||||
app_state,
|
app_state,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
} else {
|
} else if let Page::Form(path) = &router.current {
|
||||||
let save_outcome = if let Page::Form(path) = &router.current {
|
let save_result = forms::event::save_form(app_state, path, &mut self.grpc_client).await?;
|
||||||
save(app_state, path, &mut self.grpc_client).await?
|
match save_result {
|
||||||
} else {
|
EventOutcome::DataSaved(_, msg) => msg,
|
||||||
SaveOutcome::NoChange
|
EventOutcome::Ok(msg) => msg,
|
||||||
};
|
_ => "Saved".to_string(),
|
||||||
match save_outcome {
|
|
||||||
SaveOutcome::NoChange => "No changes to save.".to_string(),
|
|
||||||
SaveOutcome::UpdatedExisting => "Entry updated.".to_string(),
|
|
||||||
SaveOutcome::CreatedNew(_) => "New entry created.".to_string(),
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
"No changes to save.".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Page::Form(path) = &router.current {
|
if let Page::Form(path) = &router.current {
|
||||||
if let Some(editor) = app_state.editor_for_path(path) {
|
if let Some(editor) = app_state.editor_for_path(path) {
|
||||||
editor.cleanup_cursor()?;
|
editor.cleanup_cursor()?;
|
||||||
@@ -918,8 +915,8 @@ impl EventHandler {
|
|||||||
}
|
}
|
||||||
terminal.cleanup()?;
|
terminal.cleanup()?;
|
||||||
Ok(EventOutcome::Exit(format!(
|
Ok(EventOutcome::Exit(format!(
|
||||||
"{}. Exiting application.",
|
"{}. Exiting application.",
|
||||||
message
|
message
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
"revert" => {
|
"revert" => {
|
||||||
@@ -933,7 +930,7 @@ impl EventHandler {
|
|||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
if let Page::Form(path) = &router.current {
|
if let Page::Form(path) = &router.current {
|
||||||
revert(app_state, path, &mut self.grpc_client).await?
|
return forms::event::revert_form(app_state, path, &mut self.grpc_client).await;
|
||||||
} else {
|
} else {
|
||||||
"Nothing to revert".to_string()
|
"Nothing to revert".to_string()
|
||||||
}
|
}
|
||||||
|
|||||||
62
client/src/pages/forms/event.rs
Normal file
62
client/src/pages/forms/event.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// src/pages/forms/event.rs
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use crossterm::event::Event;
|
||||||
|
use canvas::keymap::KeyEventOutcome;
|
||||||
|
use crate::{
|
||||||
|
state::app::state::AppState,
|
||||||
|
pages::forms::{FormState, logic},
|
||||||
|
modes::handlers::event::EventOutcome,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn handle_form_event(
|
||||||
|
event: Event,
|
||||||
|
app_state: &mut AppState,
|
||||||
|
path: &str,
|
||||||
|
ideal_cursor_column: &mut usize,
|
||||||
|
) -> Result<EventOutcome> {
|
||||||
|
if let Event::Key(key_event) = event {
|
||||||
|
if let Some(editor) = app_state.editor_for_path(path) {
|
||||||
|
match editor.handle_key_event(key_event) {
|
||||||
|
KeyEventOutcome::Consumed(Some(msg)) => {
|
||||||
|
return Ok(EventOutcome::Ok(msg));
|
||||||
|
}
|
||||||
|
KeyEventOutcome::Consumed(None) => {
|
||||||
|
return Ok(EventOutcome::Ok("Form input updated".into()));
|
||||||
|
}
|
||||||
|
KeyEventOutcome::Pending => {
|
||||||
|
return Ok(EventOutcome::Ok("Waiting for next key...".into()));
|
||||||
|
}
|
||||||
|
KeyEventOutcome::NotMatched => {
|
||||||
|
// fall through to navigation / save / revert
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(EventOutcome::Ok(String::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save wrapper
|
||||||
|
pub async fn save_form(
|
||||||
|
app_state: &mut AppState,
|
||||||
|
path: &str,
|
||||||
|
grpc_client: &mut crate::services::grpc_client::GrpcClient,
|
||||||
|
) -> Result<EventOutcome> {
|
||||||
|
let outcome = logic::save(app_state, path, grpc_client).await?;
|
||||||
|
let message = match outcome {
|
||||||
|
logic::SaveOutcome::NoChange => "No changes to save.".to_string(),
|
||||||
|
logic::SaveOutcome::UpdatedExisting => "Entry updated.".to_string(),
|
||||||
|
logic::SaveOutcome::CreatedNew(_) => "New entry created.".to_string(),
|
||||||
|
};
|
||||||
|
Ok(EventOutcome::DataSaved(outcome, message))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn revert_form(
|
||||||
|
app_state: &mut AppState,
|
||||||
|
path: &str,
|
||||||
|
grpc_client: &mut crate::services::grpc_client::GrpcClient,
|
||||||
|
) -> Result<EventOutcome> {
|
||||||
|
let message = logic::revert(app_state, path, grpc_client).await?;
|
||||||
|
Ok(EventOutcome::Ok(message))
|
||||||
|
}
|
||||||
39
client/src/pages/forms/loader.rs
Normal file
39
client/src/pages/forms/loader.rs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// src/pages/forms/loader.rs
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use crate::{
|
||||||
|
state::app::state::AppState,
|
||||||
|
services::grpc_client::GrpcClient,
|
||||||
|
services::ui_service::UiService, // ✅ import UiService
|
||||||
|
config::binds::Config,
|
||||||
|
pages::forms::FormState,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn ensure_form_loaded_and_count(
|
||||||
|
grpc_client: &mut GrpcClient,
|
||||||
|
app_state: &mut AppState,
|
||||||
|
config: &Config,
|
||||||
|
profile: &str,
|
||||||
|
table: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
let path = format!("{}/{}", profile, table);
|
||||||
|
|
||||||
|
app_state.ensure_form_editor(&path, config, || {
|
||||||
|
FormState::new(profile.to_string(), table.to_string(), vec![])
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(form_state) = app_state.form_state_for_path(&path) {
|
||||||
|
UiService::fetch_and_set_table_count(grpc_client, form_state)
|
||||||
|
.await
|
||||||
|
.context("Failed to fetch table count")?;
|
||||||
|
|
||||||
|
if form_state.total_count > 0 {
|
||||||
|
UiService::load_table_data_by_position(grpc_client, form_state)
|
||||||
|
.await
|
||||||
|
.context("Failed to load table data")?;
|
||||||
|
} else {
|
||||||
|
form_state.reset_to_empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -3,7 +3,11 @@
|
|||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod logic;
|
pub mod logic;
|
||||||
|
pub mod event;
|
||||||
|
pub mod loader;
|
||||||
|
|
||||||
pub use ui::*;
|
pub use ui::*;
|
||||||
pub use state::*;
|
pub use state::*;
|
||||||
pub use logic::*;
|
pub use logic::*;
|
||||||
|
pub use event::*;
|
||||||
|
pub use loader::*;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use crate::pages::admin::AdminState;
|
|||||||
use crate::pages::admin::AdminFocus;
|
use crate::pages::admin::AdminFocus;
|
||||||
use crate::pages::intro::IntroState;
|
use crate::pages::intro::IntroState;
|
||||||
use crate::pages::forms::{FormState, FieldDefinition};
|
use crate::pages::forms::{FormState, FieldDefinition};
|
||||||
|
use crate::pages::forms;
|
||||||
use crate::pages::routing::{Router, Page};
|
use crate::pages::routing::{Router, Page};
|
||||||
use crate::buffer::state::BufferState;
|
use crate::buffer::state::BufferState;
|
||||||
use crate::buffer::state::AppView;
|
use crate::buffer::state::AppView;
|
||||||
@@ -459,7 +460,7 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Page::Form(current_path) = &router.current {
|
if let Page::Form(_current_path) = &router.current {
|
||||||
let current_view_profile = app_state.current_view_profile_name.clone();
|
let current_view_profile = app_state.current_view_profile_name.clone();
|
||||||
let current_view_table = app_state.current_view_table_name.clone();
|
let current_view_table = app_state.current_view_table_name.clone();
|
||||||
|
|
||||||
@@ -475,52 +476,16 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
);
|
);
|
||||||
needs_redraw = true;
|
needs_redraw = true;
|
||||||
|
|
||||||
match UiService::load_table_view(
|
// DELEGATE to the forms loader
|
||||||
|
match forms::loader::ensure_form_loaded_and_count(
|
||||||
&mut grpc_client,
|
&mut grpc_client,
|
||||||
&mut app_state,
|
&mut app_state,
|
||||||
|
&config,
|
||||||
prof_name,
|
prof_name,
|
||||||
tbl_name,
|
tbl_name,
|
||||||
)
|
).await {
|
||||||
.await
|
Ok(()) => {
|
||||||
{
|
app_state.hide_dialog();
|
||||||
Ok(new_form_state) => {
|
|
||||||
// Set the new form state and fetch count
|
|
||||||
let path = format!("{}/{}", prof_name, tbl_name);
|
|
||||||
app_state.ensure_form_editor(&path, &config, || new_form_state);
|
|
||||||
|
|
||||||
if let Some(form_state) = app_state.form_state_for_path(&path) {
|
|
||||||
if let Err(e) = UiService::fetch_and_set_table_count(
|
|
||||||
&mut grpc_client,
|
|
||||||
form_state,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
app_state.update_dialog_content(
|
|
||||||
&format!("Error fetching count: {}", e),
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::LoginFailed,
|
|
||||||
);
|
|
||||||
} else if form_state.total_count > 0 {
|
|
||||||
if let Err(e) = UiService::load_table_data_by_position(
|
|
||||||
&mut grpc_client,
|
|
||||||
form_state,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
app_state.update_dialog_content(
|
|
||||||
&format!("Error loading data: {}", e),
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::LoginFailed,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
app_state.hide_dialog();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
form_state.reset_to_empty();
|
|
||||||
app_state.hide_dialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prev_view_profile_name = current_view_profile;
|
prev_view_profile_name = current_view_profile;
|
||||||
prev_view_table_name = current_view_table;
|
prev_view_table_name = current_view_table;
|
||||||
table_just_switched = true;
|
table_just_switched = true;
|
||||||
@@ -531,10 +496,9 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
vec!["OK".to_string()],
|
vec!["OK".to_string()],
|
||||||
DialogPurpose::LoginFailed,
|
DialogPurpose::LoginFailed,
|
||||||
);
|
);
|
||||||
app_state.current_view_profile_name =
|
// Reset to previous state on error
|
||||||
prev_view_profile_name.clone();
|
app_state.current_view_profile_name = prev_view_profile_name.clone();
|
||||||
app_state.current_view_table_name =
|
app_state.current_view_table_name = prev_view_table_name.clone();
|
||||||
prev_view_table_name.clone();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user