diff --git a/frontend/src/lib/components/common/confirmationModal/DraftSyncConflictModal.svelte b/frontend/src/lib/components/common/confirmationModal/DraftSyncConflictModal.svelte index 772d69d4a9..7ee8c10bcd 100644 --- a/frontend/src/lib/components/common/confirmationModal/DraftSyncConflictModal.svelte +++ b/frontend/src/lib/components/common/confirmationModal/DraftSyncConflictModal.svelte @@ -61,7 +61,7 @@

- Someone else (another tab, browser, or teammate) saved a newer version of this draft. Your + Someone else (another tab, browser or AI Agent) saved a newer version of this draft. Your autosave was rejected to avoid overwriting their work.

{#if conflictHandle.conflict} diff --git a/frontend/src/lib/components/common/confirmationModal/OtherUsersDraftsModal.svelte b/frontend/src/lib/components/common/confirmationModal/OtherUsersDraftsModal.svelte index 0609f16bef..34de1723f8 100644 --- a/frontend/src/lib/components/common/confirmationModal/OtherUsersDraftsModal.svelte +++ b/frontend/src/lib/components/common/confirmationModal/OtherUsersDraftsModal.svelte @@ -97,7 +97,7 @@ // Bypass the autosave debouncer so the fork lands on the // server BEFORE we navigate. The destination route loads // via `getDraft=true` and 404s if no draft yet exists at - // the fork path — the prior `UserDraft.save` call + // the fork path — `UserDraft.save` alone would have // scheduled a debounced POST 1.5s out, so a fresh nav was // always too early. await UserDraftDbSyncer.save({ @@ -107,6 +107,12 @@ value, immediate: true }) + // Close the banner BEFORE the navigation so the user sees the + // modal disappear on click. Without this the modal stays + // visible during the navigation tear-down — Svelte hasn't + // torn down the previous route's components by the time + // `goto` returns, so the banner lingers on top of the + // destination editor for a beat. isOpen = false goto(editPathFor(target)) } catch (e) { @@ -122,6 +128,7 @@ title="Other users are currently working on {path}" fixedWidth="sm" fixedHeight="sm" + closeOnOutsideClick={!jsonOpen} >
diff --git a/frontend/src/lib/components/common/modal/Modal2.svelte b/frontend/src/lib/components/common/modal/Modal2.svelte index 13e36af170..1b29b93b9a 100644 --- a/frontend/src/lib/components/common/modal/Modal2.svelte +++ b/frontend/src/lib/components/common/modal/Modal2.svelte @@ -17,6 +17,11 @@ fixedWidth?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' fixedHeight?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' contentClasses?: string + /** Close when the user clicks outside the modal body. Default + * true. Set false when the caller stacks a child modal on top + * and clicks "outside" the child would otherwise propagate + * here and close the underlying modal. */ + closeOnOutsideClick?: boolean headerLeft?: import('svelte').Snippet headerRight?: import('svelte').Snippet children?: import('svelte').Snippet @@ -33,6 +38,7 @@ fixedWidth = 'md', fixedHeight = 'md', contentClasses = '', + closeOnOutsideClick = true, headerLeft, headerRight, children @@ -64,6 +70,7 @@ } function handleKeyDown(event: KeyboardEvent) { + if (!isOpen) return if (event.key === 'Escape') { event.preventDefault() event.stopPropagation() @@ -94,7 +101,9 @@ css?.popup?.class, 'wm-modal-form-popup' )} - use:clickOutside={{ onClickOutside: () => close() }} + use:clickOutside={{ + onClickOutside: () => closeOnOutsideClick && close() + }} >