mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 00:02:19 +00:00
feat: prompt browser confirmation on page exit with unsaved changes (#9503)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+36
-22
@@ -38,6 +38,26 @@
|
||||
let open = $state(false)
|
||||
let goingTo: URL | undefined = $state(undefined)
|
||||
|
||||
// Mirrors the modal condition: dirty when values differ, or when either
|
||||
// value is missing (e.g. a never-saved draft). Also refreshes
|
||||
// savedValue/modifiedValue for the diff drawer.
|
||||
function hasUnsavedChanges(): boolean {
|
||||
const state = getInitialAndModifiedValues?.()
|
||||
savedValue = state?.savedValue
|
||||
modifiedValue = state?.modifiedValue
|
||||
|
||||
if (savedValue && modifiedValue) {
|
||||
const draftOrDeployed = cleanValueProperties((savedValue.draft || savedValue) ?? {})
|
||||
const current = cleanValueProperties(modifiedValue ?? {})
|
||||
|
||||
return (
|
||||
orderedJsonStringify(replaceFalseWithUndefined(draftOrDeployed)) !==
|
||||
orderedJsonStringify(replaceFalseWithUndefined(current))
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
beforeNavigate(async (newNavigationState) => {
|
||||
if (
|
||||
!bypassBeforeNavigate &&
|
||||
@@ -49,38 +69,32 @@
|
||||
) {
|
||||
goingTo = newNavigationState.to.url
|
||||
|
||||
const state = getInitialAndModifiedValues?.()
|
||||
savedValue = state?.savedValue
|
||||
modifiedValue = state?.modifiedValue
|
||||
|
||||
async function openModal() {
|
||||
if (hasUnsavedChanges()) {
|
||||
newNavigationState.cancel()
|
||||
open = true
|
||||
}
|
||||
if (savedValue && modifiedValue) {
|
||||
const draftOrDeployed = cleanValueProperties((savedValue.draft || savedValue) ?? {})
|
||||
const current = cleanValueProperties(modifiedValue ?? {})
|
||||
|
||||
if (
|
||||
orderedJsonStringify(replaceFalseWithUndefined(draftOrDeployed)) ===
|
||||
orderedJsonStringify(replaceFalseWithUndefined(current))
|
||||
) {
|
||||
if (!tabMode) {
|
||||
bypassBeforeNavigate = true
|
||||
}
|
||||
additionalExitAction?.()
|
||||
} else {
|
||||
await openModal()
|
||||
}
|
||||
} else {
|
||||
await openModal()
|
||||
if (!tabMode) {
|
||||
bypassBeforeNavigate = true
|
||||
}
|
||||
additionalExitAction?.()
|
||||
}
|
||||
} else if (bypassBeforeNavigate) {
|
||||
bypassBeforeNavigate = false
|
||||
}
|
||||
})
|
||||
|
||||
function onBeforeUnload(event: BeforeUnloadEvent) {
|
||||
if (!bypassBeforeNavigate && getInitialAndModifiedValues && hasUnsavedChanges()) {
|
||||
// Triggers the browser's native "leave site?" confirmation
|
||||
event.preventDefault()
|
||||
// Required by some browsers (legacy mechanism)
|
||||
event.returnValue = true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window onbeforeunload={onBeforeUnload} />
|
||||
|
||||
{#if open}
|
||||
<div
|
||||
style="display: none"
|
||||
|
||||
Reference in New Issue
Block a user