fixed form state removed, but not won, aint working yet
This commit is contained in:
@@ -50,7 +50,7 @@ move_right = ["l", "Right"]
|
||||
move_down = ["j", "Down"]
|
||||
# Optional
|
||||
move_line_end = ["$"]
|
||||
# move_word_next = ["w"]
|
||||
move_word_next = ["w"]
|
||||
next_field = ["Tab"]
|
||||
move_word_prev = ["b"]
|
||||
move_word_end = ["e"]
|
||||
|
||||
@@ -18,7 +18,6 @@ pub async fn handle_command_event(
|
||||
app_state: &mut AppState,
|
||||
login_state: &LoginState,
|
||||
register_state: &RegisterState,
|
||||
form_state: &mut FormState,
|
||||
command_input: &mut String,
|
||||
command_message: &mut String,
|
||||
grpc_client: &mut GrpcClient,
|
||||
@@ -38,7 +37,6 @@ pub async fn handle_command_event(
|
||||
if config.is_command_execute(key.code, key.modifiers) {
|
||||
return process_command(
|
||||
config,
|
||||
form_state,
|
||||
app_state,
|
||||
login_state,
|
||||
register_state,
|
||||
@@ -73,7 +71,6 @@ pub async fn handle_command_event(
|
||||
|
||||
async fn process_command(
|
||||
config: &Config,
|
||||
form_state: &mut FormState,
|
||||
app_state: &mut AppState,
|
||||
login_state: &LoginState,
|
||||
register_state: &RegisterState,
|
||||
@@ -103,7 +100,6 @@ async fn process_command(
|
||||
action,
|
||||
terminal,
|
||||
app_state,
|
||||
form_state,
|
||||
login_state,
|
||||
register_state,
|
||||
)
|
||||
@@ -118,7 +114,6 @@ async fn process_command(
|
||||
"save" => {
|
||||
let outcome = save(
|
||||
app_state,
|
||||
form_state,
|
||||
grpc_client,
|
||||
).await?;
|
||||
let message = match outcome {
|
||||
@@ -131,7 +126,7 @@ async fn process_command(
|
||||
},
|
||||
"revert" => {
|
||||
let message = revert(
|
||||
form_state,
|
||||
app_state,
|
||||
grpc_client,
|
||||
).await?;
|
||||
command_input.clear();
|
||||
|
||||
@@ -15,13 +15,12 @@ impl CommandHandler {
|
||||
&mut self,
|
||||
action: &str,
|
||||
terminal: &mut TerminalCore,
|
||||
app_state: &AppState,
|
||||
form_state: &FormState,
|
||||
app_state: &mut AppState,
|
||||
login_state: &LoginState,
|
||||
register_state: &RegisterState,
|
||||
) -> Result<(bool, String)> {
|
||||
match action {
|
||||
"quit" => self.handle_quit(terminal, app_state, form_state, login_state, register_state).await,
|
||||
"quit" => self.handle_quit(terminal, app_state, login_state, register_state).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,8 +30,7 @@ impl CommandHandler {
|
||||
async fn handle_quit(
|
||||
&self,
|
||||
terminal: &mut TerminalCore,
|
||||
app_state: &AppState,
|
||||
form_state: &FormState,
|
||||
app_state: &mut AppState,
|
||||
login_state: &LoginState,
|
||||
register_state: &RegisterState,
|
||||
) -> Result<(bool, String)> {
|
||||
@@ -41,8 +39,10 @@ impl CommandHandler {
|
||||
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 {
|
||||
form_state.has_unsaved_changes
|
||||
false
|
||||
};
|
||||
|
||||
if !has_unsaved {
|
||||
|
||||
@@ -17,7 +17,6 @@ use anyhow::Result;
|
||||
pub async fn handle_navigation_event(
|
||||
key: KeyEvent,
|
||||
config: &Config,
|
||||
form_state: &mut FormState,
|
||||
app_state: &mut AppState,
|
||||
login_state: &mut LoginState,
|
||||
register_state: &mut RegisterState,
|
||||
@@ -52,11 +51,15 @@ pub async fn handle_navigation_event(
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
"next_field" => {
|
||||
next_field(form_state);
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
next_field(fs);
|
||||
}
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
"prev_field" => {
|
||||
prev_field(form_state);
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
prev_field(fs);
|
||||
}
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
"enter_command_mode" => {
|
||||
|
||||
@@ -220,66 +220,90 @@ impl EventHandler {
|
||||
async fn handle_search_palette_event(
|
||||
&mut self,
|
||||
key_event: KeyEvent,
|
||||
form_state: &mut FormState,
|
||||
app_state: &mut AppState,
|
||||
) -> Result<EventOutcome> {
|
||||
let mut should_close = false;
|
||||
let mut outcome_message = String::new();
|
||||
let mut trigger_search = false;
|
||||
|
||||
if let Some(search_state) = app_state.search_state.as_mut() {
|
||||
match key_event.code {
|
||||
KeyCode::Esc => {
|
||||
should_close = true;
|
||||
outcome_message = "Search cancelled".to_string();
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
if let Some(selected_hit) =
|
||||
search_state.results.get(search_state.selected_index)
|
||||
{
|
||||
if let Ok(data) = serde_json::from_str::<
|
||||
std::collections::HashMap<String, String>,
|
||||
>(&selected_hit.content_json)
|
||||
{
|
||||
let detached_pos = form_state.total_count + 2;
|
||||
form_state
|
||||
.update_from_response(&data, detached_pos);
|
||||
}
|
||||
// Step 1: Handle search_state logic in a short scope
|
||||
let (maybe_data, maybe_id) = {
|
||||
if let Some(search_state) = app_state.search_state.as_mut() {
|
||||
match key_event.code {
|
||||
KeyCode::Esc => {
|
||||
should_close = true;
|
||||
outcome_message =
|
||||
format!("Loaded record ID {}", selected_hit.id);
|
||||
outcome_message = "Search cancelled".to_string();
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
KeyCode::Up => search_state.previous_result(),
|
||||
KeyCode::Down => search_state.next_result(),
|
||||
KeyCode::Char(c) => {
|
||||
search_state
|
||||
.input
|
||||
.insert(search_state.cursor_position, c);
|
||||
search_state.cursor_position += 1;
|
||||
trigger_search = true;
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
if search_state.cursor_position > 0 {
|
||||
search_state.cursor_position -= 1;
|
||||
search_state.input.remove(search_state.cursor_position);
|
||||
trigger_search = true;
|
||||
KeyCode::Enter => {
|
||||
if let Some(selected_hit) =
|
||||
search_state.results.get(search_state.selected_index)
|
||||
{
|
||||
if let Ok(data) = serde_json::from_str::<
|
||||
std::collections::HashMap<String, String>,
|
||||
>(&selected_hit.content_json)
|
||||
{
|
||||
(Some(data), Some(selected_hit.id))
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
KeyCode::Left => {
|
||||
search_state.cursor_position =
|
||||
search_state.cursor_position.saturating_sub(1);
|
||||
}
|
||||
KeyCode::Right => {
|
||||
if search_state.cursor_position < search_state.input.len()
|
||||
{
|
||||
KeyCode::Up => {
|
||||
search_state.previous_result();
|
||||
(None, None)
|
||||
}
|
||||
KeyCode::Down => {
|
||||
search_state.next_result();
|
||||
(None, None)
|
||||
}
|
||||
KeyCode::Char(c) => {
|
||||
search_state.input.insert(search_state.cursor_position, c);
|
||||
search_state.cursor_position += 1;
|
||||
trigger_search = true;
|
||||
(None, None)
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
if search_state.cursor_position > 0 {
|
||||
search_state.cursor_position -= 1;
|
||||
search_state.input.remove(search_state.cursor_position);
|
||||
trigger_search = true;
|
||||
}
|
||||
(None, None)
|
||||
}
|
||||
KeyCode::Left => {
|
||||
search_state.cursor_position =
|
||||
search_state.cursor_position.saturating_sub(1);
|
||||
(None, None)
|
||||
}
|
||||
KeyCode::Right => {
|
||||
if search_state.cursor_position < search_state.input.len() {
|
||||
search_state.cursor_position += 1;
|
||||
}
|
||||
(None, None)
|
||||
}
|
||||
_ => (None, None),
|
||||
}
|
||||
_ => {}
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
};
|
||||
|
||||
if trigger_search {
|
||||
// Step 2: Now safe to borrow form_state
|
||||
if let (Some(data), Some(id)) = (maybe_data, maybe_id) {
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
let detached_pos = fs.total_count + 2;
|
||||
fs.update_from_response(&data, detached_pos);
|
||||
}
|
||||
should_close = true;
|
||||
outcome_message = format!("Loaded record ID {}", id);
|
||||
}
|
||||
|
||||
// Step 3: Trigger async search if needed
|
||||
if trigger_search {
|
||||
if let Some(search_state) = app_state.search_state.as_mut() {
|
||||
search_state.is_loading = true;
|
||||
search_state.results.clear();
|
||||
search_state.selected_index = 0;
|
||||
@@ -289,10 +313,7 @@ impl EventHandler {
|
||||
let sender = self.search_result_sender.clone();
|
||||
let mut grpc_client = self.grpc_client.clone();
|
||||
|
||||
info!(
|
||||
"--- 1. Spawning search task for query: '{}' ---",
|
||||
query
|
||||
);
|
||||
info!("--- 1. Spawning search task for query: '{}' ---", query);
|
||||
tokio::spawn(async move {
|
||||
info!("--- 2. Background task started. ---");
|
||||
match grpc_client.search_table(table_name, query).await {
|
||||
@@ -328,7 +349,6 @@ impl EventHandler {
|
||||
config: &Config,
|
||||
terminal: &mut TerminalCore,
|
||||
command_handler: &mut CommandHandler,
|
||||
form_state: &mut FormState,
|
||||
auth_state: &mut AuthState,
|
||||
login_state: &mut LoginState,
|
||||
register_state: &mut RegisterState,
|
||||
@@ -339,13 +359,7 @@ impl EventHandler {
|
||||
) -> Result<EventOutcome> {
|
||||
if app_state.ui.show_search_palette {
|
||||
if let Event::Key(key_event) = event {
|
||||
return self
|
||||
.handle_search_palette_event(
|
||||
key_event,
|
||||
form_state,
|
||||
app_state,
|
||||
)
|
||||
.await;
|
||||
return self.handle_search_palette_event(key_event, app_state).await;
|
||||
}
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
@@ -570,7 +584,6 @@ impl EventHandler {
|
||||
let nav_outcome = navigation::handle_navigation_event(
|
||||
key_event,
|
||||
config,
|
||||
form_state,
|
||||
app_state,
|
||||
login_state,
|
||||
register_state,
|
||||
@@ -580,9 +593,7 @@ impl EventHandler {
|
||||
&mut self.command_input,
|
||||
&mut self.command_message,
|
||||
&mut self.navigation_state,
|
||||
)
|
||||
.await;
|
||||
|
||||
).await;
|
||||
match nav_outcome {
|
||||
Ok(EventOutcome::ButtonSelected { context, index }) => {
|
||||
let message = match context {
|
||||
@@ -692,7 +703,6 @@ impl EventHandler {
|
||||
return self
|
||||
.handle_core_action(
|
||||
action,
|
||||
form_state,
|
||||
auth_state,
|
||||
login_state,
|
||||
register_state,
|
||||
@@ -739,7 +749,6 @@ impl EventHandler {
|
||||
return self
|
||||
.handle_core_action(
|
||||
action,
|
||||
form_state,
|
||||
auth_state,
|
||||
login_state,
|
||||
register_state,
|
||||
@@ -792,15 +801,18 @@ impl EventHandler {
|
||||
}
|
||||
|
||||
if config.is_command_execute(key_code, modifiers) {
|
||||
let mut current_position = form_state.current_position;
|
||||
let total_count = form_state.total_count;
|
||||
let (mut current_position, total_count) = if let Some(fs) = app_state.form_state() {
|
||||
(fs.current_position, fs.total_count)
|
||||
} else {
|
||||
(1, 0)
|
||||
};
|
||||
|
||||
let outcome = command_mode::handle_command_event(
|
||||
key_event,
|
||||
config,
|
||||
app_state,
|
||||
login_state,
|
||||
register_state,
|
||||
form_state,
|
||||
&mut self.command_input,
|
||||
&mut self.command_message,
|
||||
&mut self.grpc_client,
|
||||
@@ -808,9 +820,10 @@ impl EventHandler {
|
||||
terminal,
|
||||
&mut current_position,
|
||||
total_count,
|
||||
)
|
||||
.await?;
|
||||
form_state.current_position = current_position;
|
||||
).await?;
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
fs.current_position = current_position;
|
||||
}
|
||||
self.command_mode = false;
|
||||
self.key_sequence_tracker.reset();
|
||||
let new_mode = ModeManager::derive_mode(
|
||||
@@ -921,7 +934,6 @@ impl EventHandler {
|
||||
async fn handle_core_action(
|
||||
&mut self,
|
||||
action: &str,
|
||||
form_state: &mut FormState,
|
||||
auth_state: &mut AuthState,
|
||||
login_state: &mut LoginState,
|
||||
register_state: &mut RegisterState,
|
||||
@@ -940,12 +952,15 @@ impl EventHandler {
|
||||
.await?;
|
||||
Ok(EventOutcome::Ok(message))
|
||||
} else {
|
||||
let save_outcome = crate::tui::functions::common::form::save(
|
||||
app_state,
|
||||
form_state,
|
||||
&mut self.grpc_client,
|
||||
)
|
||||
.await?;
|
||||
let save_outcome = if let Some(fs) = app_state.form_state_mut() {
|
||||
crate::tui::functions::common::form::save(
|
||||
app_state,
|
||||
&mut self.grpc_client,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
SaveOutcome::NoChange
|
||||
};
|
||||
let message = match save_outcome {
|
||||
SaveOutcome::NoChange => "No changes to save.".to_string(),
|
||||
SaveOutcome::UpdatedExisting => "Entry updated.".to_string(),
|
||||
@@ -975,10 +990,8 @@ impl EventHandler {
|
||||
} else {
|
||||
let save_outcome = crate::tui::functions::common::form::save(
|
||||
app_state,
|
||||
form_state,
|
||||
&mut self.grpc_client,
|
||||
)
|
||||
.await?;
|
||||
).await?;
|
||||
match save_outcome {
|
||||
SaveOutcome::NoChange => "No changes to save.".to_string(),
|
||||
SaveOutcome::UpdatedExisting => "Entry updated.".to_string(),
|
||||
@@ -1003,13 +1016,17 @@ impl EventHandler {
|
||||
register_state,
|
||||
app_state,
|
||||
)
|
||||
.await
|
||||
.await
|
||||
} else {
|
||||
crate::tui::functions::common::form::revert(
|
||||
form_state,
|
||||
&mut self.grpc_client,
|
||||
)
|
||||
.await?
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
crate::tui::functions::common::form::revert(
|
||||
app_state,
|
||||
&mut self.grpc_client,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
"Nothing to revert".to_string()
|
||||
}
|
||||
};
|
||||
Ok(EventOutcome::Ok(message))
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// src/tui/functions/common/form.rs
|
||||
|
||||
use crate::services::grpc_client::GrpcClient;
|
||||
use crate::state::app::state::AppState; // NEW: Import AppState
|
||||
use crate::state::pages::form::FormState;
|
||||
use crate::utils::data_converter; // NEW: Import our translator
|
||||
use crate::state::app::state::AppState;
|
||||
use crate::utils::data_converter;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -14,143 +12,137 @@ pub enum SaveOutcome {
|
||||
CreatedNew(i64),
|
||||
}
|
||||
|
||||
// MODIFIED save function signature and logic
|
||||
pub async fn save(
|
||||
app_state: &AppState, // NEW: Pass in AppState
|
||||
form_state: &mut FormState,
|
||||
app_state: &mut AppState,
|
||||
grpc_client: &mut GrpcClient,
|
||||
) -> Result<SaveOutcome> {
|
||||
if !form_state.has_unsaved_changes {
|
||||
return Ok(SaveOutcome::NoChange);
|
||||
}
|
||||
|
||||
// --- NEW: VALIDATION & CONVERSION STEP ---
|
||||
let cache_key =
|
||||
format!("{}.{}", form_state.profile_name, form_state.table_name);
|
||||
let schema = match app_state.schema_cache.get(&cache_key) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
return Err(anyhow!(
|
||||
"Schema for table '{}' not found in cache. Cannot save.",
|
||||
form_state.table_name
|
||||
));
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
if !fs.has_unsaved_changes {
|
||||
return Ok(SaveOutcome::NoChange);
|
||||
}
|
||||
};
|
||||
|
||||
let data_map: HashMap<String, String> = form_state
|
||||
.fields
|
||||
.iter()
|
||||
.zip(form_state.values.iter())
|
||||
.map(|(field_def, value)| (field_def.data_key.clone(), value.clone()))
|
||||
.collect();
|
||||
// Copy out what we need before dropping the mutable borrow
|
||||
let profile_name = fs.profile_name.clone();
|
||||
let table_name = fs.table_name.clone();
|
||||
let fields = fs.fields.clone();
|
||||
let values = fs.values.clone();
|
||||
let id = fs.id;
|
||||
let total_count = fs.total_count;
|
||||
let current_position = fs.current_position;
|
||||
|
||||
// Use our new translator. It returns a user-friendly error on failure.
|
||||
let converted_data =
|
||||
match data_converter::convert_and_validate_data(&data_map, schema) {
|
||||
Ok(data) => data,
|
||||
Err(user_error) => return Err(anyhow!(user_error)),
|
||||
let cache_key = format!("{}.{}", profile_name, table_name);
|
||||
let schema = app_state
|
||||
.schema_cache
|
||||
.get(&cache_key)
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Schema for table '{}' not found in cache. Cannot save.",
|
||||
table_name
|
||||
)
|
||||
})?;
|
||||
|
||||
let data_map: HashMap<String, String> = fields
|
||||
.iter()
|
||||
.zip(values.iter())
|
||||
.map(|(field_def, value)| (field_def.data_key.clone(), value.clone()))
|
||||
.collect();
|
||||
|
||||
let converted_data =
|
||||
data_converter::convert_and_validate_data(&data_map, schema)
|
||||
.map_err(|user_error| anyhow!(user_error))?;
|
||||
|
||||
let is_new_entry = id == 0
|
||||
|| (total_count > 0 && current_position > total_count)
|
||||
|| (total_count == 0 && current_position == 1);
|
||||
|
||||
let outcome = if is_new_entry {
|
||||
let response = grpc_client
|
||||
.post_table_data(profile_name.clone(), table_name.clone(), converted_data)
|
||||
.await
|
||||
.context("Failed to post new table data")?;
|
||||
|
||||
if response.success {
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
fs.id = response.inserted_id;
|
||||
fs.total_count += 1;
|
||||
fs.current_position = fs.total_count;
|
||||
fs.has_unsaved_changes = false;
|
||||
}
|
||||
SaveOutcome::CreatedNew(response.inserted_id)
|
||||
} else {
|
||||
return Err(anyhow!("Server failed to insert data: {}", response.message));
|
||||
}
|
||||
} else {
|
||||
if id == 0 {
|
||||
return Err(anyhow!(
|
||||
"Cannot update record: ID is 0, but not classified as new entry."
|
||||
));
|
||||
}
|
||||
let response = grpc_client
|
||||
.put_table_data(profile_name.clone(), table_name.clone(), id, converted_data)
|
||||
.await
|
||||
.context("Failed to put (update) table data")?;
|
||||
|
||||
if response.success {
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
fs.has_unsaved_changes = false;
|
||||
}
|
||||
SaveOutcome::UpdatedExisting
|
||||
} else {
|
||||
return Err(anyhow!("Server failed to update data: {}", response.message));
|
||||
}
|
||||
};
|
||||
// --- END OF NEW STEP ---
|
||||
|
||||
let outcome: SaveOutcome;
|
||||
let is_new_entry = form_state.id == 0
|
||||
|| (form_state.total_count > 0
|
||||
&& form_state.current_position > form_state.total_count)
|
||||
|| (form_state.total_count == 0 && form_state.current_position == 1);
|
||||
|
||||
if is_new_entry {
|
||||
let response = grpc_client
|
||||
.post_table_data(
|
||||
form_state.profile_name.clone(),
|
||||
form_state.table_name.clone(),
|
||||
converted_data, // Use the validated & converted data
|
||||
)
|
||||
.await
|
||||
.context("Failed to post new table data")?;
|
||||
|
||||
if response.success {
|
||||
form_state.id = response.inserted_id;
|
||||
form_state.total_count += 1;
|
||||
form_state.current_position = form_state.total_count;
|
||||
outcome = SaveOutcome::CreatedNew(response.inserted_id);
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
"Server failed to insert data: {}",
|
||||
response.message
|
||||
));
|
||||
}
|
||||
Ok(outcome)
|
||||
} else {
|
||||
if form_state.id == 0 {
|
||||
return Err(anyhow!(
|
||||
"Cannot update record: ID is 0, but not classified as new entry."
|
||||
));
|
||||
}
|
||||
let response = grpc_client
|
||||
.put_table_data(
|
||||
form_state.profile_name.clone(),
|
||||
form_state.table_name.clone(),
|
||||
form_state.id,
|
||||
converted_data, // Use the validated & converted data
|
||||
)
|
||||
.await
|
||||
.context("Failed to put (update) table data")?;
|
||||
|
||||
if response.success {
|
||||
outcome = SaveOutcome::UpdatedExisting;
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
"Server failed to update data: {}",
|
||||
response.message
|
||||
));
|
||||
}
|
||||
Ok(SaveOutcome::NoChange)
|
||||
}
|
||||
|
||||
form_state.has_unsaved_changes = false;
|
||||
Ok(outcome)
|
||||
}
|
||||
|
||||
pub async fn revert(
|
||||
form_state: &mut FormState, // Takes &mut FormState to update it
|
||||
app_state: &mut AppState,
|
||||
grpc_client: &mut GrpcClient,
|
||||
) -> Result<String> {
|
||||
if form_state.id == 0 || (form_state.total_count > 0 && form_state.current_position > form_state.total_count) || (form_state.total_count == 0 && form_state.current_position == 1) {
|
||||
let old_total_count = form_state.total_count; // Preserve for correct new position
|
||||
form_state.reset_to_empty(); // reset_to_empty will clear values and set id=0
|
||||
form_state.total_count = old_total_count; // Restore total_count
|
||||
if form_state.total_count > 0 { // Correctly set current_position for new
|
||||
form_state.current_position = form_state.total_count + 1;
|
||||
} else {
|
||||
form_state.current_position = 1;
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
if fs.id == 0
|
||||
|| (fs.total_count > 0 && fs.current_position > fs.total_count)
|
||||
|| (fs.total_count == 0 && fs.current_position == 1)
|
||||
{
|
||||
let old_total_count = fs.total_count;
|
||||
fs.reset_to_empty();
|
||||
fs.total_count = old_total_count;
|
||||
if fs.total_count > 0 {
|
||||
fs.current_position = fs.total_count + 1;
|
||||
} else {
|
||||
fs.current_position = 1;
|
||||
}
|
||||
return Ok("New entry cleared".to_string());
|
||||
}
|
||||
return Ok("New entry cleared".to_string());
|
||||
}
|
||||
|
||||
if form_state.current_position == 0 || form_state.current_position > form_state.total_count {
|
||||
if form_state.total_count > 0 {
|
||||
form_state.current_position = 1;
|
||||
} else {
|
||||
// No records to revert to, effectively a new entry state.
|
||||
form_state.reset_to_empty();
|
||||
return Ok("No saved data to revert to; form cleared.".to_string());
|
||||
if fs.current_position == 0 || fs.current_position > fs.total_count {
|
||||
if fs.total_count > 0 {
|
||||
fs.current_position = 1;
|
||||
} else {
|
||||
fs.reset_to_empty();
|
||||
return Ok("No saved data to revert to; form cleared.".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
let response = grpc_client
|
||||
.get_table_data_by_position(
|
||||
fs.profile_name.clone(),
|
||||
fs.table_name.clone(),
|
||||
fs.current_position as i32,
|
||||
)
|
||||
.await
|
||||
.context(format!(
|
||||
"Failed to get table data by position {} for table {}.{}",
|
||||
fs.current_position, fs.profile_name, fs.table_name
|
||||
))?;
|
||||
|
||||
fs.update_from_response(&response.data, fs.current_position);
|
||||
Ok("Changes discarded, reloaded last saved version".to_string())
|
||||
} else {
|
||||
Ok("Nothing to revert".to_string())
|
||||
}
|
||||
|
||||
let response = grpc_client
|
||||
.get_table_data_by_position(
|
||||
form_state.profile_name.clone(),
|
||||
form_state.table_name.clone(),
|
||||
form_state.current_position as i32,
|
||||
)
|
||||
.await
|
||||
.context(format!(
|
||||
"Failed to get table data by position {} for table {}.{}",
|
||||
form_state.current_position,
|
||||
form_state.profile_name,
|
||||
form_state.table_name
|
||||
))?;
|
||||
|
||||
// FIX: Pass the current position as the second argument
|
||||
form_state.update_from_response(&response.data, form_state.current_position);
|
||||
Ok("Changes discarded, reloaded last saved version".to_string())
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ use crate::ui::handlers::context::DialogPurpose;
|
||||
use crate::tui::functions::common::login;
|
||||
use crate::tui::functions::common::register;
|
||||
use crate::utils::columns::filter_user_columns;
|
||||
use canvas::keymap::KeyEventOutcome;
|
||||
use anyhow::{Context, Result};
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
use crossterm::event as crossterm_event;
|
||||
@@ -193,33 +194,48 @@ pub async fn run_ui() -> Result<()> {
|
||||
if crossterm_event::poll(std::time::Duration::from_millis(1))? {
|
||||
let event = event_reader.read_event().context("Failed to read terminal event")?;
|
||||
event_processed = true;
|
||||
let event_outcome_result = {
|
||||
// We need to avoid borrowing app_state twice, so we'll need to modify the handle_event call
|
||||
// For now, let's create a temporary approach
|
||||
let mut temp_form_state = app_state.form_state_mut().unwrap().clone();
|
||||
let result = event_handler.handle_event(
|
||||
event,
|
||||
&config,
|
||||
&mut terminal,
|
||||
&mut command_handler,
|
||||
&mut temp_form_state,
|
||||
&mut auth_state,
|
||||
&mut login_state,
|
||||
&mut register_state,
|
||||
&mut intro_state,
|
||||
&mut admin_state,
|
||||
&mut buffer_state,
|
||||
&mut app_state,
|
||||
).await;
|
||||
|
||||
// Update the app_state with any changes from temp_form_state
|
||||
if let Some(form_state) = app_state.form_state_mut() {
|
||||
*form_state = temp_form_state;
|
||||
if let crossterm_event::Event::Key(key_event) = &event {
|
||||
if app_state.ui.show_form {
|
||||
if let Some(editor) = app_state.form_editor.as_mut() {
|
||||
match editor.handle_key_event(*key_event) {
|
||||
KeyEventOutcome::Consumed(Some(msg)) => {
|
||||
event_handler.command_message = msg;
|
||||
needs_redraw = true;
|
||||
continue;
|
||||
}
|
||||
KeyEventOutcome::Consumed(None) => {
|
||||
needs_redraw = true;
|
||||
continue;
|
||||
}
|
||||
KeyEventOutcome::Pending => {
|
||||
needs_redraw = true;
|
||||
continue;
|
||||
}
|
||||
KeyEventOutcome::NotMatched => {
|
||||
// fall through to client-level handling
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
};
|
||||
// Get form state from app_state and pass to handle_event
|
||||
let form_state = app_state.form_state_mut().unwrap();
|
||||
|
||||
let event_outcome_result = event_handler.handle_event(
|
||||
event,
|
||||
&config,
|
||||
&mut terminal,
|
||||
&mut command_handler,
|
||||
&mut auth_state,
|
||||
&mut login_state,
|
||||
&mut register_state,
|
||||
&mut intro_state,
|
||||
&mut admin_state,
|
||||
&mut buffer_state,
|
||||
&mut app_state,
|
||||
).await;
|
||||
let mut should_exit = false;
|
||||
match event_outcome_result {
|
||||
Ok(outcome) => match outcome {
|
||||
|
||||
Reference in New Issue
Block a user