feat: Prevent form navigation with unsaved changes

This commit is contained in:
filipriec
2025-04-07 12:03:17 +02:00
parent 5a3067c8e5
commit 173c4c98b8
2 changed files with 24 additions and 12 deletions

View File

@@ -27,13 +27,16 @@ pub fn render_canvas(
.split(area); .split(area);
// Input container styling // Input container styling
let border_style = if form_state.has_unsaved_changes() {
Style::default().fg(theme.warning)
} else if is_edit_mode {
Style::default().fg(theme.accent)
} else {
Style::default().fg(theme.secondary)
};
let input_container = Block::default() let input_container = Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(if is_edit_mode { .border_style(border_style)
form_state.has_unsaved_changes().then(|| theme.warning).unwrap_or(theme.accent)
} else {
theme.secondary
})
.style(Style::default().bg(theme.bg)); .style(Style::default().bg(theme.bg));
// Input block dimensions // Input block dimensions

View File

@@ -11,13 +11,22 @@ pub async fn handle_action(
total_count: u64, total_count: u64,
ideal_cursor_column: &mut usize, ideal_cursor_column: &mut usize,
) -> Result<String, Box<dyn std::error::Error>> { ) -> Result<String, Box<dyn std::error::Error>> {
// TODO store unsaved changes without deleting form state values
// First check for unsaved changes in both cases
if form_state.has_unsaved_changes() {
return Ok(
"Unsaved changes. Save (Ctrl+S) or Revert (Ctrl+R) before navigating."
.to_string(),
);
}
match action { match action {
"previous_entry" => { "previous_entry" => {
let new_position = current_position.saturating_sub(1); let new_position = current_position.saturating_sub(1);
if new_position >= 1 { if new_position >= 1 {
*current_position = new_position; *current_position = new_position;
let response = grpc_client.get_adresar_by_position(*current_position).await?; let response = grpc_client.get_adresar_by_position(*current_position).await?;
// Direct field assignments // Direct field assignments
form_state.id = response.id; form_state.id = response.id;
form_state.values = vec![ form_state.values = vec![
@@ -27,14 +36,14 @@ pub async fn handle_action(
response.skladm, response.ico, response.kontakt, response.skladm, response.ico, response.kontakt,
response.telefon, response.skladu, response.fax, response.telefon, response.skladu, response.fax,
]; ];
let current_input = form_state.get_current_input(); let current_input = form_state.get_current_input();
let max_cursor_pos = if !current_input.is_empty() { let max_cursor_pos = if !current_input.is_empty() {
current_input.len() - 1 current_input.len() - 1
} else { 0 }; } else { 0 };
form_state.current_cursor_pos = std::cmp::min(*ideal_cursor_column, max_cursor_pos); form_state.current_cursor_pos = std::cmp::min(*ideal_cursor_column, max_cursor_pos);
form_state.has_unsaved_changes = false; form_state.has_unsaved_changes = false;
Ok(format!("Loaded form entry {}", *current_position)) Ok(format!("Loaded form entry {}", *current_position))
} else { } else {
Ok("Already at first form entry".into()) Ok("Already at first form entry".into())
@@ -45,7 +54,7 @@ pub async fn handle_action(
*current_position += 1; *current_position += 1;
if *current_position <= total_count { if *current_position <= total_count {
let response = grpc_client.get_adresar_by_position(*current_position).await?; let response = grpc_client.get_adresar_by_position(*current_position).await?;
// Direct field assignments // Direct field assignments
form_state.id = response.id; form_state.id = response.id;
form_state.values = vec![ form_state.values = vec![
@@ -55,14 +64,14 @@ pub async fn handle_action(
response.skladm, response.ico, response.kontakt, response.skladm, response.ico, response.kontakt,
response.telefon, response.skladu, response.fax, response.telefon, response.skladu, response.fax,
]; ];
let current_input = form_state.get_current_input(); let current_input = form_state.get_current_input();
let max_cursor_pos = if !current_input.is_empty() { let max_cursor_pos = if !current_input.is_empty() {
current_input.len() - 1 current_input.len() - 1
} else { 0 }; } else { 0 };
form_state.current_cursor_pos = std::cmp::min(*ideal_cursor_column, max_cursor_pos); form_state.current_cursor_pos = std::cmp::min(*ideal_cursor_column, max_cursor_pos);
form_state.has_unsaved_changes = false; form_state.has_unsaved_changes = false;
Ok(format!("Loaded form entry {}", *current_position)) Ok(format!("Loaded form entry {}", *current_position))
} else { } else {
form_state.reset_to_empty(); form_state.reset_to_empty();
@@ -77,4 +86,4 @@ pub async fn handle_action(
} }
_ => Err("Unknown form action".into()) _ => Err("Unknown form action".into())
} }
} }