1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use crate::app::FormBaseline;
use crate::app::forms::HostForm;
use crate::app::tag_state::BulkTagEditorState;
/// Host-form and bulk-tag editor state grouped off the `App` god-struct.
/// Holds the add/edit host form, its dirty-check baseline, the bulk-tag
/// editor, the last-apply snapshot used by `u` to revert bulk-tag changes
/// and the pending-discard confirmation flag. Pure state container.
pub struct FormState {
pub(crate) host: HostForm,
pub(crate) host_baseline: Option<FormBaseline>,
pub(crate) bulk_tag_editor: BulkTagEditorState,
/// Snapshot of the last bulk tag apply, used by `u` to revert the
/// operation even though `undo_stack` only holds deleted hosts. Holds
/// `(alias, previous_tags)` pairs so restore is idempotent. Cleared
/// after a successful undo or on the next mutation.
pub(crate) bulk_tag_undo: Option<Vec<(String, Vec<String>)>>,
/// When true, the Esc key shows a "Discard changes?" dialog instead of
/// closing the open host form. Mutate via `request_discard_confirm`
/// and `dismiss_discard_confirm`; read via `is_discard_pending`.
discard_pending: bool,
}
impl FormState {
/// Arm the "Discard changes?" Esc dialog. Called when Esc fires on a
/// form that has unsaved edits relative to its baseline.
pub fn request_discard_confirm(&mut self) {
self.discard_pending = true;
}
/// Clear the pending discard flag. Called on dialog dismiss, on
/// successful save, and on form close.
pub fn dismiss_discard_confirm(&mut self) {
self.discard_pending = false;
}
/// True when Esc should show the "Discard changes?" dialog instead of
/// closing the form.
pub fn is_discard_pending(&self) -> bool {
self.discard_pending
}
}
impl Default for FormState {
fn default() -> Self {
Self {
host: HostForm::new(),
host_baseline: None,
bulk_tag_editor: BulkTagEditorState::default(),
bulk_tag_undo: None,
discard_pending: false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_is_empty() {
let s = FormState::default();
assert!(!s.is_discard_pending());
assert!(s.bulk_tag_undo.is_none());
assert!(s.host_baseline.is_none());
assert!(s.bulk_tag_editor.rows.is_empty());
}
#[test]
fn discard_confirm_lifecycle() {
let mut s = FormState::default();
assert!(!s.is_discard_pending());
s.request_discard_confirm();
assert!(s.is_discard_pending());
s.dismiss_discard_confirm();
assert!(!s.is_discard_pending());
}
}