feat: Prevent form navigation with unsaved changes
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user