SheetForm dirty-state confirm + wire isDirty into all form consumers (R4.5)
SheetForm gains an isDirty prop. When true, any close attempt (Cancel button, header X, Radix overlay click, Escape) opens a 'Discard changes?' ConfirmDialog instead of discarding unsaved edits. Radix dismiss callbacks (onEscapeKeyDown, onPointerDownOutside) are intercepted when dirty so the guard applies uniformly. All four form consumers now compute and pass isDirty: - ServicePage: name/enabled/config differ from the persisted instance. - Settings machine editor: field-by-field draft vs editingMachine (create mode is always dirty; secret write-only fields excluded). - Message compose: subject non-empty, body differs from default, or attachments present. - WidgetConfigDialog: draft !== null (only draft mode is guarded; list mode has nothing to discard). Tests: 3 new SheetForm dirty-guard cases (prompt on cancel, abort discard, clean close when not dirty) + one focused dirty-guard test per consumer. 122 tests pass; lint/build green. Refs openspec/changes/mobile-responsive-parity/verify-report.md residual risk #1.
This commit is contained in:
@@ -128,6 +128,30 @@ function emptyMachine(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dirty check for the machine editor SheetForm guard (spec R4.5).
|
||||
* Pragmatic field-by-field comparison of the user-editable fields. In create
|
||||
* mode (editingMachine is null) the form is always dirty.
|
||||
*/
|
||||
function isMachineDraftDirty(
|
||||
draft: MonitoringMachineInput,
|
||||
editingMachine: MonitoringMachine | null,
|
||||
): boolean {
|
||||
if (!editingMachine) return true;
|
||||
return (
|
||||
draft.name !== editingMachine.name ||
|
||||
draft.host !== editingMachine.host ||
|
||||
draft.mode !== editingMachine.mode ||
|
||||
draft.port !== editingMachine.port ||
|
||||
draft.username !== editingMachine.username ||
|
||||
draft.ssh_key_id !== editingMachine.ssh_key_id ||
|
||||
draft.enabled !== editingMachine.enabled ||
|
||||
draft.notes !== editingMachine.notes ||
|
||||
JSON.stringify([...draft.services].sort()) !==
|
||||
JSON.stringify([...editingMachine.services].sort())
|
||||
);
|
||||
}
|
||||
|
||||
function MachineEditor({
|
||||
title,
|
||||
hint,
|
||||
@@ -1159,6 +1183,7 @@ export function Settings() {
|
||||
(machineDraft.mode === "ssh" && !machineDraft.host.trim())
|
||||
}
|
||||
saveLabel={machineDraft.id ? "Save machine" : "Create machine"}
|
||||
isDirty={isMachineDraftDirty(machineDraft, editingMachine)}
|
||||
>
|
||||
<MachineEditor
|
||||
key={`${machineDraft.id ?? machineDraft.mode}-${machineDraft.mode}`}
|
||||
|
||||
Reference in New Issue
Block a user