diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index 241b105c36..af64618731 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -39,6 +39,7 @@ langToExt, updateOptions } from '$lib/editorUtils' + import { dirtyStore } from './common/confirmationModal/dirtyStore' try { StandaloneServices.initialize({ @@ -366,6 +367,8 @@ let timeoutModel: NodeJS.Timeout | undefined = undefined editor.onDidChangeModelContent((event) => { + $dirtyStore = true + timeoutModel && clearTimeout(timeoutModel) timeoutModel = setTimeout(() => { code = getCode() diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index 41edc7697c..032d9e3b63 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -16,6 +16,8 @@ import { writable } from 'svelte/store' import CenteredPage from './CenteredPage.svelte' import Button from './common/button/Button.svelte' + import { dirtyStore } from './common/confirmationModal/dirtyStore' + import UnsavedConfirmationModal from './common/confirmationModal/UnsavedConfirmationModal.svelte' import { OFFSET } from './CronInput.svelte' import FlowEditor from './flows/FlowEditor.svelte' import { flowStateStore } from './flows/flowState' @@ -48,6 +50,7 @@ async function saveFlow(): Promise { const flow = cleanInputs($flowStore) const { cron, args, enabled } = $scheduleStore + $dirtyStore = false if (initialPath === '') { await FlowService.createFlow({ @@ -155,6 +158,8 @@ loadHubScripts() + +
diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index c9fc6dceeb..4b3c6ef305 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -16,6 +16,8 @@ import ScriptSchema from './ScriptSchema.svelte' import CenteredPage from './CenteredPage.svelte' import Tooltip from './Tooltip.svelte' + import UnsavedConfirmationModal from './common/confirmationModal/UnsavedConfirmationModal.svelte' + import { dirtyStore } from './common/confirmationModal/dirtyStore' import { Button } from './common' export let script: Script @@ -41,6 +43,7 @@ async function editScript(): Promise { try { + $dirtyStore = false if (!script.schema) { await inferArgs(script.language, script.content, script.schema) } @@ -73,6 +76,7 @@ } +
diff --git a/frontend/src/lib/components/ScriptEditor.svelte b/frontend/src/lib/components/ScriptEditor.svelte index 529f52034c..924e6ae95b 100644 --- a/frontend/src/lib/components/ScriptEditor.svelte +++ b/frontend/src/lib/components/ScriptEditor.svelte @@ -24,6 +24,7 @@ import Button from './common/button/Button.svelte' import TestJobLoader from './TestJobLoader.svelte' import { onMount } from 'svelte' + import UnsavedConfirmationModal from './common/confirmationModal/UnsavedConfirmationModal.svelte' // Exported export let schema: Schema = emptySchema() diff --git a/frontend/src/lib/components/common/confirmationModal/ConfirmationModal.svelte b/frontend/src/lib/components/common/confirmationModal/ConfirmationModal.svelte index 024fdd5f5a..0a888985dc 100644 --- a/frontend/src/lib/components/common/confirmationModal/ConfirmationModal.svelte +++ b/frontend/src/lib/components/common/confirmationModal/ConfirmationModal.svelte @@ -5,6 +5,7 @@ import Icon from 'svelte-awesome' import { fade } from 'svelte/transition' import Button from '../button/Button.svelte' + import Badge from '../badge/Badge.svelte' export let title: string export let confirmationText: string @@ -12,8 +13,23 @@ export let open: boolean = false const dispatch = createEventDispatcher() + + function onKeyDown(event: KeyboardEvent) { + if (open) { + switch (event.key) { + case 'Enter': + dispatch('confirmed') + break + case 'Escape': + dispatch('canceled') + break + } + } + } + + {#if open} diff --git a/frontend/src/lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte b/frontend/src/lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte new file mode 100644 index 0000000000..dc3f9805c0 --- /dev/null +++ b/frontend/src/lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte @@ -0,0 +1,47 @@ + + + { + if (navigationState) { + navigationState.cancel() + } + navigationState = undefined + }} + on:confirmed={() => { + if (navigationState?.to) { + goto(navigationState.to) + } + $dirtyStore = false + navigationState = undefined + }} +> +
+ Are you sure you want to discard change you have made? +
+
diff --git a/frontend/src/lib/components/common/confirmationModal/dirtyStore.ts b/frontend/src/lib/components/common/confirmationModal/dirtyStore.ts new file mode 100644 index 0000000000..0429a9df43 --- /dev/null +++ b/frontend/src/lib/components/common/confirmationModal/dirtyStore.ts @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store' + +export const dirtyStore = writable(false) diff --git a/frontend/src/routes/flows/add.svelte b/frontend/src/routes/flows/add.svelte index 6822a7863b..d6d29f0ab8 100644 --- a/frontend/src/routes/flows/add.svelte +++ b/frontend/src/routes/flows/add.svelte @@ -8,6 +8,7 @@ diff --git a/frontend/src/routes/flows/edit/[...path].svelte b/frontend/src/routes/flows/edit/[...path].svelte index 0567a10633..622c89c993 100644 --- a/frontend/src/routes/flows/edit/[...path].svelte +++ b/frontend/src/routes/flows/edit/[...path].svelte @@ -14,6 +14,7 @@ import { workspaceStore } from '$lib/stores' import { decodeState, emptySchema } from '$lib/utils' import { initFlow } from '$lib/components/flows/flowStore' + import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore' const initialState = $page.url.searchParams.get('state') let flowLoadedFromUrl = initialState != undefined ? decodeState(initialState) : undefined @@ -44,6 +45,7 @@ initialPath = flow.path initFlow(flow) + $dirtyStore = false } $: { @@ -51,6 +53,8 @@ loadFlow() } } + + diff --git a/frontend/src/routes/scripts/add.svelte b/frontend/src/routes/scripts/add.svelte index e4b83013c4..f34618998a 100644 --- a/frontend/src/routes/scripts/add.svelte +++ b/frontend/src/routes/scripts/add.svelte @@ -14,6 +14,7 @@ import ScriptBuilder from '$lib/components/ScriptBuilder.svelte' import type { Schema } from '$lib/common' import { decodeState, emptySchema, getScriptByPath, sendUserToast } from '$lib/utils' + import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore' // Default let schema: Schema = emptySchema() @@ -74,6 +75,7 @@ loadTemplate() } } + $dirtyStore = true diff --git a/frontend/src/routes/scripts/edit/[...hash].svelte b/frontend/src/routes/scripts/edit/[...hash].svelte index 03cf8de622..823538a787 100644 --- a/frontend/src/routes/scripts/edit/[...hash].svelte +++ b/frontend/src/routes/scripts/edit/[...hash].svelte @@ -13,6 +13,7 @@ import { workspaceStore } from '$lib/stores' import ScriptBuilder from '$lib/components/ScriptBuilder.svelte' import { decodeState } from '$lib/utils' + import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore' const initialState = $page.url.searchParams.get('state') let scriptLoadedFromUrl = initialState != undefined ? decodeState(initialState) : undefined @@ -30,6 +31,7 @@ hash: $page.params.hash }) initialPath = script!.path + $dirtyStore = false } $: { @@ -37,6 +39,7 @@ loadScript() } } + {#if script}