fix: prevent false dirty indicator on read-only detail pages

Async component init (e.g. MultiSelect replacing <select> with hidden
inputs) mutated the DOM after the initial form state snapshot, causing
a phantom "unsaved fields" warning. Re-baseline the initial state on
structural DOM changes until the first user interaction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-22 22:27:41 +01:00
parent f8b5c8de65
commit 91d8aa5055

View File

@@ -456,12 +456,25 @@ export function initStandardDetailPage(options = {}) {
};
let formObserver = null;
let formStabilized = false;
if (unsavedIndicatorEnabled && typeof MutationObserver !== 'undefined') {
// Observe dynamic form controls (for example MultiSelect hidden inputs).
formObserver = new MutationObserver(() => {
if (!actionPolicy.isSubmitting()) {
syncUnsavedIndicator();
// Until the first user interaction, structural DOM changes (childList) are
// assumed to come from async component init (e.g. MultiSelect replacing
// <select> elements) — re-baseline instead of flagging as dirty.
formObserver = new MutationObserver((mutations) => {
if (actionPolicy.isSubmitting()) {
return;
}
if (!formStabilized) {
const hasStructuralChange = mutations.some((m) => m.type === 'childList');
if (hasStructuralChange) {
initialState = createFormStateMap(form);
syncUnsavedIndicator();
return;
}
}
syncUnsavedIndicator();
});
formObserver.observe(form, {
subtree: true,
@@ -471,6 +484,10 @@ export function initStandardDetailPage(options = {}) {
});
}
const markStabilized = () => { formStabilized = true; };
form.addEventListener('input', markStabilized, { once: true });
form.addEventListener('change', markStabilized, { once: true });
const onKeyDown = (event) => {
if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey) {
return;