diff --git a/frontend/src/lib/components/ResourceEditor.svelte b/frontend/src/lib/components/ResourceEditor.svelte
index 933eee5f71..7fed7ace78 100644
--- a/frontend/src/lib/components/ResourceEditor.svelte
+++ b/frontend/src/lib/components/ResourceEditor.svelte
@@ -5,7 +5,6 @@
import { createEventDispatcher, untrack } from 'svelte'
import { userStore, workspaceStore } from '$lib/stores'
import { sendUserToast } from '$lib/toast'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { clearJsonSchemaResourceCache } from './schema/jsonSchemaResource.svelte'
import ResourceForm from './ResourceForm.svelte'
import { invalidateWorkspacePaths } from './PathNameAutocomplete.svelte'
@@ -259,48 +258,24 @@
// draft (if any) sits in `.draft` as the editor's internal
// `ResourceState` shape — the editor reads it directly.
const savedDraftState = (r as any).draft as ResourceState | undefined
- if (r.is_draft) {
- notifyDraftLoaded({
- workspace: ws,
- itemKind: 'resource',
- path: initialPath ?? '',
- draftOnly: r.no_deployed,
- onResetToDeployed: async () => {
- const fresh = await ResourceService.getResource({
- workspace: ws,
- path: initialPath ?? ''
- })
- const deployed: ResourceState = {
- path: fresh.path,
- description: fresh.description ?? '',
- args: (fresh.value ?? {}) as any,
- labels: fresh.labels ?? undefined,
- wsSpecific: fresh.ws_specific ?? false
- }
- fetchedResources[ws] = fresh
- fetchedRev[ws] = fresh.edited_at
- initialStates[ws] = structuredClone(deployed)
- // Reset the live cell to the deployed state and drop the
- // DB autosave. Setting the draft to `undefined` would
- // blank the cell (and the editor) — `discard` reseeds it
- // with the deployed baseline instead. The rev is re-recorded
- // by the seeding effect on the user's next edit.
- UserDraft.discard('resource', initialPath ?? '', deployed, { workspace: ws })
- }
- })
- }
fetchedResources[ws] = r
fetchedRev[ws] = r.edited_at
- // Translate the deployed wire shape into the editor's
- // `ResourceState` shape. When a saved draft exists, use it
- // directly — it's already a `ResourceState`.
- const s: ResourceState = savedDraftState ?? {
+ // The deployed baseline, translated into the editor's
+ // `ResourceState` shape. Kept as the dirty-check reference
+ // so the "unsaved changes" banner compares draft-vs-deployed
+ // instead of loaded-vs-current — when a saved draft exists,
+ // the form opens with `draft != deployed` so the banner
+ // fires immediately, exactly as if the user had typed.
+ const deployedState: ResourceState = {
path: r.path,
description: r.description ?? '',
args: (r.value ?? {}) as any,
labels: r.labels ?? undefined,
wsSpecific: r.ws_specific ?? false
}
+ // What the editor opens with: the saved draft if present,
+ // otherwise the deployed.
+ const s: ResourceState = savedDraftState ?? deployedState
// Reconcile the local autosave with the backend before the
// handle is registered. If the backend moved on since the
// autosave was written (recorded rev != current rev) surface
@@ -330,7 +305,7 @@
}
}
ensureHandle(ws, s)
- initialStates[ws] = structuredClone(s)
+ initialStates[ws] = structuredClone(deployedState)
existedInitially[ws] = true
perWsUser[ws] = user
// Keep resource_type in sync for the base workspace (controls the schema)
diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte
index 4efb5e9a03..12605ddd9d 100644
--- a/frontend/src/lib/components/ScriptBuilder.svelte
+++ b/frontend/src/lib/components/ScriptBuilder.svelte
@@ -80,6 +80,7 @@
import DefaultScripts from './DefaultScripts.svelte'
import { getContext, onMount, setContext, untrack } from 'svelte'
import EditorHeader from './EditorHeader.svelte'
+ import AutosaveIndicator from './AutosaveIndicator.svelte'
import LabelsInput from './LabelsInput.svelte'
import DeployOverrideConfirmationModal from '$lib/components/common/confirmationModal/DeployOverrideConfirmationModal.svelte'
@@ -354,6 +355,7 @@
// new drafts). Resumed in the async `.finally` so language
// switches AFTER bootstrap (which also call `initContent`) sync
// normally.
+ console.log('Suspending autosave for script bootstrap', userDraftPath)
UserDraft.stopSync('script', userDraftPath)
if (template === 'wac_python') {
script.modules = {
@@ -1837,6 +1839,9 @@
onNavigate={(item) => onNavigate?.(item)}
/>
{/if}
+ {#if $workspaceStore}
+
+ {/if}
diff --git a/frontend/src/lib/components/VariableEditor.svelte b/frontend/src/lib/components/VariableEditor.svelte
index fe052ac3bd..297dc7ef97 100644
--- a/frontend/src/lib/components/VariableEditor.svelte
+++ b/frontend/src/lib/components/VariableEditor.svelte
@@ -7,7 +7,6 @@
import DrawerContent from './common/drawer/DrawerContent.svelte'
import Alert from './common/alert/Alert.svelte'
import { sendUserToast } from '$lib/toast'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { canWrite } from '$lib/utils'
import { Save } from 'lucide-svelte'
import VariableForm from './VariableForm.svelte'
@@ -172,44 +171,14 @@
// draft (if any) sits in `.draft` as the editor's internal
// `VariableState` shape — the editor reads it directly.
const savedDraftState = (v as any).draft as VariableState | undefined
- if (v.is_draft) {
- notifyDraftLoaded({
- workspace: ws,
- itemKind: 'variable',
- path: p,
- draftOnly: v.no_deployed,
- onResetToDeployed: async () => {
- const fresh = await VariableService.getVariable({
- workspace: ws,
- path: p,
- decryptSecret: false
- })
- const deployed: VariableState = {
- path: fresh.path,
- variable: {
- value: fresh.value ?? '',
- is_secret: fresh.is_secret,
- description: fresh.description ?? ''
- },
- labels: fresh.labels ?? undefined,
- wsSpecific: fresh.ws_specific ?? false
- }
- fetchedRev[ws] = fresh.edited_at
- initialStates[ws] = structuredClone(deployed)
- // Reset the live cell to the deployed state and drop the
- // DB autosave. Setting the draft to `undefined` would
- // blank the cell (and the editor) — `discard` reseeds it
- // with the deployed baseline instead. The rev is re-recorded
- // by the seeding effect on the user's next edit.
- UserDraft.discard('variable', editPath ?? '', deployed, { workspace: ws })
- }
- })
- }
fetchedRev[ws] = v.edited_at
- // Translate the deployed wire shape into the editor's
- // `VariableState` shape. When a saved draft exists, use it
- // directly — it's already a `VariableState`.
- const s: VariableState = savedDraftState ?? {
+ // The deployed baseline, translated into the editor's
+ // `VariableState` shape. Kept as the dirty-check reference
+ // so the "unsaved changes" banner compares draft-vs-deployed
+ // instead of loaded-vs-current — when a saved draft exists,
+ // the form opens with `draft != deployed` so the banner
+ // fires immediately, exactly as if the user had typed.
+ const deployedState: VariableState = {
path: v.path,
variable: {
value: v.value ?? '',
@@ -219,6 +188,9 @@
labels: v.labels ?? undefined,
wsSpecific: v.ws_specific ?? false
}
+ // What the editor opens with: the saved draft if present,
+ // otherwise the deployed.
+ const s: VariableState = savedDraftState ?? deployedState
// See ResourceEditor for the same pattern: a backend that
// moved on since the autosave was written → staleness modal;
// otherwise just a "showing your local autosave" toast with
@@ -237,7 +209,7 @@
}
}
ensureHandle(ws, s)
- initialStates[ws] = structuredClone(s)
+ initialStates[ws] = structuredClone(deployedState)
existedInitially[ws] = true
extraPerms[ws] = v.extra_perms ?? {}
perWsUser[ws] = user
diff --git a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte
index 34e0b42d5a..4ec9728155 100644
--- a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte
@@ -5,7 +5,6 @@
import Path from '$lib/components/Path.svelte'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { withForkConflictRetry } from '$lib/utils/forkConflict'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -136,11 +135,12 @@
itemKind = isFlow ? 'flow' : 'script'
edit = true
dirtyPath = false
- await loadTrigger(defaultValues)
+ const draftOverlay = await loadTrigger(defaultValues)
+ originalConfig = structuredClone($state.snapshot(getAzureConfig()))
+ if (draftOverlay) loadTriggerConfig(draftOverlay)
if (!defaultValues) {
initialConfig = structuredClone($state.snapshot(getAzureConfig()))
}
- originalConfig = structuredClone($state.snapshot(getAzureConfig()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load Azure trigger: ${err.body}`, true)
@@ -185,41 +185,28 @@
}
}
+ /** See `NatsTriggerEditorInner.loadTrigger` for the rationale. */
async function loadTrigger(
- defaultConfig?: Record,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Record
+ ): Promise | undefined> {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
- return
+ return undefined
}
try {
const s = await AzureTriggerService.getAzureTrigger({
workspace: $workspaceStore!,
path: initialPath,
- getDraft
+ getDraft: true
})
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_azure',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed at the field
- // level so `loadTriggerConfig` sees the editor's last-saved state.
const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
- loadTriggerConfig(effective)
+ loadTriggerConfig(deployedTrigger)
+ return draftFromBackend
+ ? ({ ...deployedTrigger, ...draftFromBackend } as Record)
+ : undefined
} catch (error) {
sendUserToast(`Could not load Azure trigger: ${error.body}`, true)
+ return undefined
}
}
diff --git a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte
index 157da3ffa5..8202f19a1a 100644
--- a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte
@@ -15,7 +15,6 @@
} from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import Section from '$lib/components/Section.svelte'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -132,12 +131,16 @@
edit = true
dirtyPath = false
dirtyLocalPart = false
- await loadTrigger(defaultConfig)
+ const draftOverlay = await loadTrigger(defaultConfig)
+ // Form holds DEPLOYED here. Capture `originalConfig` as the
+ // deployed baseline so `hasChanged` (= current != originalConfig)
+ // fires whenever a draft exists, not only after the user edits.
+ originalConfig = structuredClone($state.snapshot(getEmailTriggerConfig())) as NewEmailTrigger
+ if (draftOverlay) loadTriggerConfig(draftOverlay as Partial)
if (!defaultConfig) {
// If the email trigger is loaded from the backend, we to set the initial config
- initialConfig = structuredClone($state.snapshot(getEmailTriggerConfig()))
+ initialConfig = structuredClone($state.snapshot(getEmailTriggerConfig())) as NewEmailTrigger
}
- originalConfig = structuredClone($state.snapshot(getEmailTriggerConfig()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load email trigger: ${err}`, true)
@@ -207,40 +210,29 @@
preservePermissionedAs = !!cfg?.permissioned_as
}
+ /**
+ * Apply the deployed config to the form, then return the saved-draft
+ * overlay (if any) so the caller can capture the deployed-only form
+ * state as `originalConfig` BEFORE applying the draft. See
+ * `NatsTriggerEditorInner` for the rationale.
+ */
async function loadTrigger(
- defaultConfig?: Partial,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Partial
+ ): Promise | undefined> {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
- return
- } else {
- const s = await EmailTriggerService.getEmailTrigger({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_email',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed at the field
- // level so `loadTriggerConfig` sees the editor's last-saved state.
- const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective: any = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
-
- loadTriggerConfig(effective)
+ return undefined
}
+ const s = await EmailTriggerService.getEmailTrigger({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
+ loadTriggerConfig(deployedTrigger)
+ return draftFromBackend
+ ? ({ ...deployedTrigger, ...draftFromBackend } as Record)
+ : undefined
}
async function triggerScript(): Promise {
diff --git a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte
index 5fd984d54e..2afcb643b2 100644
--- a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte
@@ -5,7 +5,6 @@
import Path from '$lib/components/Path.svelte'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { withForkConflictRetry } from '$lib/utils/forkConflict'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -138,11 +137,12 @@
itemKind = isFlow ? 'flow' : 'script'
edit = true
dirtyPath = false
- await loadTrigger(defaultValues)
+ const draftOverlay = await loadTrigger(defaultValues)
+ originalConfig = structuredClone($state.snapshot(getGcpConfig()))
+ if (draftOverlay) loadTriggerConfig(draftOverlay)
if (!defaultValues) {
initialConfig = structuredClone($state.snapshot(getGcpConfig()))
}
- originalConfig = structuredClone($state.snapshot(getGcpConfig()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load GCP Pub/Sub trigger: ${err.body}`, true)
@@ -189,42 +189,28 @@
}
}
+ /** See `NatsTriggerEditorInner.loadTrigger` for the rationale. */
async function loadTrigger(
- defaultConfig?: Record,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Record
+ ): Promise | undefined> {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
- return
- } else {
- try {
- const s = await GcpTriggerService.getGcpTrigger({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_gcp',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed at the field
- // level so `loadTriggerConfig` sees the editor's last-saved state.
- const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
- loadTriggerConfig(effective)
- } catch (error) {
- sendUserToast(`Could not load GCP Pub/Sub trigger: ${error.body}`, true)
- }
+ return undefined
+ }
+ try {
+ const s = await GcpTriggerService.getGcpTrigger({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
+ loadTriggerConfig(deployedTrigger)
+ return draftFromBackend
+ ? ({ ...deployedTrigger, ...draftFromBackend } as Record)
+ : undefined
+ } catch (error) {
+ sendUserToast(`Could not load GCP Pub/Sub trigger: ${error.body}`, true)
+ return undefined
}
}
diff --git a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte
index 8a8a332d41..38ac33b729 100644
--- a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte
@@ -23,7 +23,6 @@
generateRandomString,
sendUserToast
} from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import Section from '$lib/components/Section.svelte'
import { Loader2, Pipette, Plus } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -231,12 +230,13 @@
edit = true
dirtyPath = false
dirtyRoutePath = false
- await loadTrigger(defaultConfig)
+ const draftOverlay = await loadTrigger(defaultConfig)
+ originalConfig = structuredClone($state.snapshot(getRouteConfig())) as NewHttpTrigger
+ if (draftOverlay) loadTriggerConfig(draftOverlay as Partial)
if (!defaultConfig) {
// If the route is loaded from the backend, we to set the initial config
- initialConfig = structuredClone($state.snapshot(getRouteConfig()))
+ initialConfig = structuredClone($state.snapshot(getRouteConfig())) as NewHttpTrigger
}
- originalConfig = structuredClone($state.snapshot(getRouteConfig()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load route: ${err}`, true)
@@ -340,40 +340,24 @@
preservePermissionedAs = !!cfg?.permissioned_as
}
+ /** See `NatsTriggerEditorInner.loadTrigger` for the rationale. */
async function loadTrigger(
- defaultConfig?: Partial,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Partial
+ ): Promise | undefined> {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
- return
- } else {
- const s = await HttpTriggerService.getHttpTrigger({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_http',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed at the field
- // level so `loadTriggerConfig` sees the editor's last-saved state.
- const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective: any = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
-
- loadTriggerConfig(effective)
+ return undefined
}
+ const s = await HttpTriggerService.getHttpTrigger({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
+ loadTriggerConfig(deployedTrigger)
+ return draftFromBackend
+ ? ({ ...deployedTrigger, ...draftFromBackend } as Record)
+ : undefined
}
async function triggerScript(): Promise {
diff --git a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte
index 10d24d8e68..95fac48422 100644
--- a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte
@@ -9,7 +9,6 @@
import { KafkaTriggerService, type ErrorHandler, type Retry, type TriggerMode } from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2, RotateCcw } from 'lucide-svelte'
@@ -160,11 +159,12 @@
itemKind = isFlow ? 'flow' : 'script'
edit = true
dirtyPath = false
- await loadTrigger(defaultConfig)
+ const draftOverlay = await loadTrigger(defaultConfig)
+ originalConfig = structuredClone($state.snapshot(getSaveCfg()))
+ if (draftOverlay) loadTriggerConfig(draftOverlay)
if (!defaultConfig) {
initialConfig = structuredClone($state.snapshot(getSaveCfg()))
}
- originalConfig = structuredClone($state.snapshot(getSaveCfg()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load Kafka trigger: ${err}`, true)
@@ -246,39 +246,24 @@
preservePermissionedAs = !!cfg?.permissioned_as
}
+ /** See `NatsTriggerEditorInner.loadTrigger` for the rationale. */
async function loadTrigger(
- defaultConfig?: Record,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Record
+ ): Promise | undefined> {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
- return
- } else {
- const s = await KafkaTriggerService.getKafkaTrigger({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_kafka',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed at the field
- // level so `loadTriggerConfig` sees the editor's last-saved state.
- const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
- loadTriggerConfig(effective)
+ return undefined
}
+ const s = await KafkaTriggerService.getKafkaTrigger({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
+ loadTriggerConfig(deployedTrigger)
+ return draftFromBackend
+ ? ({ ...deployedTrigger, ...draftFromBackend } as Record)
+ : undefined
}
function getSaveCfg(): Record {
diff --git a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte
index eed0747859..a16bc802a6 100644
--- a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte
@@ -8,7 +8,6 @@
import ScriptPicker from '$lib/components/ScriptPicker.svelte'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2 } from 'lucide-svelte'
@@ -156,11 +155,12 @@
itemKind = isFlow ? 'flow' : 'script'
edit = true
dirtyPath = false
- await loadTrigger(defaultConfig)
+ const draftOverlay = await loadTrigger(defaultConfig)
+ originalConfig = structuredClone($state.snapshot(getSaveCfg()))
+ if (draftOverlay) loadTriggerConfig(draftOverlay)
if (!defaultConfig) {
initialConfig = structuredClone($state.snapshot(getSaveCfg()))
}
- originalConfig = structuredClone($state.snapshot(getSaveCfg()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load mqtt trigger: ${err.body}`, true)
@@ -245,42 +245,28 @@
}
}
+ /** See `NatsTriggerEditorInner.loadTrigger` for the rationale. */
async function loadTrigger(
- defaultConfig?: Record,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Record
+ ): Promise | undefined> {
try {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
- return
- } else {
- const s = await MqttTriggerService.getMqttTrigger({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_mqtt',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed at the field
- // level so `loadTriggerConfig` sees the editor's last-saved state.
- const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
- loadTriggerConfig(effective)
+ return undefined
}
+ const s = await MqttTriggerService.getMqttTrigger({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
+ loadTriggerConfig(deployedTrigger)
+ return draftFromBackend
+ ? ({ ...deployedTrigger, ...draftFromBackend } as Record)
+ : undefined
} catch (error) {
sendUserToast(`Could not load mqtt trigger: ${error.body}`, true)
+ return undefined
}
}
diff --git a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte
index bb6adf9bac..88d6419069 100644
--- a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte
@@ -8,7 +8,6 @@
import { NatsTriggerService, type ErrorHandler, type Retry, type TriggerMode } from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2 } from 'lucide-svelte'
@@ -144,11 +143,18 @@
itemKind = isFlow ? 'flow' : 'script'
edit = true
dirtyPath = false
- await loadTrigger(defaultConfig)
+ const draftOverlay = await loadTrigger(defaultConfig)
+ // At this point the form holds the DEPLOYED config (or
+ // `defaultConfig` for new triggers). Capture `originalConfig`
+ // here so `hasChanged` (= `current != originalConfig`) compares
+ // against the deployed baseline; if a draft exists, applying
+ // the overlay below makes `current != originalConfig` fire
+ // the "unsaved changes" banner immediately.
+ originalConfig = structuredClone($state.snapshot(getSaveCfg()))
+ if (draftOverlay) loadTriggerConfig(draftOverlay)
if (!defaultConfig) {
initialConfig = structuredClone($state.snapshot(getSaveCfg()))
}
- originalConfig = structuredClone($state.snapshot(getSaveCfg()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load nats trigger: ${err}`, true)
@@ -228,39 +234,32 @@
preservePermissionedAs = !!cfg?.permissioned_as
}
+ /**
+ * Apply the deployed config to the form, then return the saved-draft
+ * overlay (if any) so the caller can capture the deployed-only form
+ * state as `originalConfig` BEFORE applying the draft. The
+ * "unsaved changes" banner compares `current` vs `originalConfig`,
+ * so capturing originalConfig from the deployed-only form makes the
+ * banner fire whenever a draft is present (instead of only after
+ * the user starts editing on top of the draft).
+ */
async function loadTrigger(
- defaultConfig?: Record,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Record
+ ): Promise | undefined> {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
- return
- } else {
- const s = await NatsTriggerService.getNatsTrigger({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_nats',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed at the field
- // level so `loadTriggerConfig` sees the editor's last-saved state.
- const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
- loadTriggerConfig(effective)
+ return undefined
}
+ const s = await NatsTriggerService.getNatsTrigger({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
+ loadTriggerConfig(deployedTrigger)
+ return draftFromBackend
+ ? ({ ...deployedTrigger, ...draftFromBackend } as Record)
+ : undefined
}
function getSaveCfg() {
diff --git a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte
index e1f6c7516e..f421dcc31c 100644
--- a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte
@@ -15,7 +15,6 @@
} from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, emptyString, emptyStringTrimmed, sendUserToast } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2 } from 'lucide-svelte'
@@ -251,11 +250,12 @@
relations = []
transaction_to_track = []
tab = 'basic'
- await loadTrigger(defaultConfig)
+ const draftOverlay = await loadTrigger(defaultConfig)
+ originalConfig = structuredClone($state.snapshot(getSaveCfg()))
+ if (draftOverlay) loadTriggerConfig(draftOverlay)
if (!defaultConfig) {
initialConfig = structuredClone($state.snapshot(getSaveCfg()))
}
- originalConfig = structuredClone($state.snapshot(getSaveCfg()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load postgres trigger: ${err.body}`, true)
@@ -368,52 +368,62 @@
preservePermissionedAs = !!cfg?.permissioned_as
}
+ /**
+ * Apply the deployed config to the form (incl. publication fetch),
+ * then return the saved-draft overlay (already merged with the
+ * publication payload) so the caller can capture the deployed-only
+ * form state as `originalConfig` BEFORE applying the draft. See
+ * `NatsTriggerEditorInner.loadTrigger` for the broader rationale.
+ *
+ * Postgres-specific wrinkle: the publication payload is fetched from
+ * the resource — keyed by `postgres_resource_path` /
+ * `publication_name`, which the draft may have changed. Fetch once
+ * using the effective values so the overlay reflects the draft's
+ * publication, not the deployed one.
+ */
async function loadTrigger(
- defaultConfig?: Record,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Record
+ ): Promise | undefined> {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
if (defaultConfig?.publication) {
transaction_to_track = [...defaultConfig.publication.transaction_to_track]
relations = defaultConfig.publication.table_to_track ?? []
}
- return
- } else {
- const s = await PostgresTriggerService.getPostgresTrigger({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_postgres',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed before the
- // publication fetch — the draft might have changed
- // `postgres_resource_path` / `publication_name`, which are the
- // keys we look up the publication by.
- const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
-
- const publication_data = await PostgresTriggerService.getPostgresPublication({
- path: effective.postgres_resource_path,
- workspace: $workspaceStore!,
- publication: effective.publication_name
- })
-
- loadTriggerConfig({ ...effective, publication: publication_data })
+ return undefined
}
+ const s = await PostgresTriggerService.getPostgresTrigger({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
+
+ // Fetch deployed publication and apply deployed config — this
+ // becomes the `originalConfig` baseline for the dirty check.
+ const deployedPublication = await PostgresTriggerService.getPostgresPublication({
+ path: deployedTrigger.postgres_resource_path,
+ workspace: $workspaceStore!,
+ publication: deployedTrigger.publication_name
+ })
+ loadTriggerConfig({ ...deployedTrigger, publication: deployedPublication })
+
+ if (!draftFromBackend) return undefined
+
+ // Draft may have changed the resource/publication keys; fetch
+ // the publication that matches the effective values so the
+ // overlay opens on the draft's view.
+ const effective = { ...deployedTrigger, ...draftFromBackend }
+ const effectivePublication =
+ effective.postgres_resource_path === deployedTrigger.postgres_resource_path &&
+ effective.publication_name === deployedTrigger.publication_name
+ ? deployedPublication
+ : await PostgresTriggerService.getPostgresPublication({
+ path: effective.postgres_resource_path,
+ workspace: $workspaceStore!,
+ publication: effective.publication_name
+ })
+ return { ...effective, publication: effectivePublication }
}
function getCaptureConfig() {
diff --git a/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte b/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte
index 2117264f23..add6fc1ff2 100644
--- a/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte
@@ -25,7 +25,6 @@
} from '$lib/gen'
import { enterpriseLicense, userStore, workspaceStore } from '$lib/stores'
import { canWrite, emptyString, formatCron, sendUserToast, cronV1toV2 } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { base } from '$lib/base'
import Section from '$lib/components/Section.svelte'
import { List, Loader2, Save, AlertTriangle } from 'lucide-svelte'
@@ -153,11 +152,15 @@
initialPath = ePath
itemKind = isFlow ? 'flow' : 'script'
path = defaultCfg?.path ?? ePath
- await loadSchedule(defaultCfg)
+ const draftOverlay = await loadSchedule(defaultCfg)
edit = true
if (!defaultCfg) {
+ // Form holds DEPLOYED here. Capture `initialConfig` as the
+ // deployed baseline so the dirty check / unsaved banner
+ // fires whenever a saved draft exists.
initialConfig = structuredClone($state.snapshot(getScheduleCfg()))
}
+ if (draftOverlay) await loadScheduleCfg(draftOverlay)
await draftSync.maybeRestore()
} finally {
clearTimeout(loadingTimeout)
@@ -294,23 +297,10 @@
path: schedule_path,
getDraft
})
- if (resp.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_schedule',
- path: schedule_path,
- draftOnly: resp.no_deployed,
- onResetToDeployed: async () => {
- await openNew(nis_flow, initial_script_path, defaultValues, schedule_path, {
- getDraft: false
- })
- }
- })
- }
// The autosaved draft (when present) sits in `.draft` as the
// editor's saved Schedule shape. Layer it over the deployed
- // at the field level so downstream `loadScheduleCfg` sees
- // the editor's last-saved state.
+ // at the field level so the inline form assignments below
+ // see the editor's last-saved state.
const { draft: draftFromBackend, ...deployedSchedule } = resp as any
s = draftFromBackend
? ({ ...deployedSchedule, ...draftFromBackend } as Schedule)
@@ -477,41 +467,36 @@
}
}
+ /**
+ * Apply the deployed schedule config to the form, then return the
+ * saved-draft overlay (if any) so the caller can capture the
+ * deployed-only form state as `initialConfig` BEFORE applying the
+ * draft. The "unsaved changes" banner compares `current` vs
+ * `initialConfig` (via `useTriggerDraftSync.deployed`), so capturing
+ * from the deployed-only form makes the banner fire whenever a
+ * draft is present.
+ */
async function loadSchedule(
- defaultCfg?: Record,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
- if (!defaultCfg) {
- try {
- const s = await ScheduleService.getSchedule({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_schedule',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadSchedule(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed so
- // `loadScheduleCfg` sees the editor's last-saved fields.
- const { draft: draftFromBackend, ...deployedSchedule } = s as any
- const effectiveSchedule = draftFromBackend
- ? { ...deployedSchedule, ...draftFromBackend }
- : deployedSchedule
- await loadScheduleCfg(effectiveSchedule)
- } catch (err) {
- sendUserToast(`Could not load schedule: ${err}`, true)
- }
- } else {
+ defaultCfg?: Record
+ ): Promise | undefined> {
+ if (defaultCfg) {
await loadScheduleCfg(defaultCfg)
+ return undefined
+ }
+ try {
+ const s = await ScheduleService.getSchedule({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedSchedule } = s as any
+ await loadScheduleCfg(deployedSchedule)
+ return draftFromBackend
+ ? ({ ...deployedSchedule, ...draftFromBackend } as Record)
+ : undefined
+ } catch (err) {
+ sendUserToast(`Could not load schedule: ${err}`, true)
+ return undefined
}
}
diff --git a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte
index d686a22d55..b6d0153375 100644
--- a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte
@@ -5,7 +5,6 @@
import Path from '$lib/components/Path.svelte'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { withForkConflictRetry } from '$lib/utils/forkConflict'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -139,14 +138,16 @@
itemKind = isFlow ? 'flow' : 'script'
edit = true
dirtyPath = false
- await loadTrigger(defaultConfig)
- // Snapshot the *backend* config as the baseline before overlaying
- // any local autosave, so hasChanged / onConfigChange correctly
- // flag the local edits as unsaved changes.
+ const draftOverlay = await loadTrigger(defaultConfig)
+ // Snapshot the *deployed* config as the baseline before
+ // overlaying the saved draft, so hasChanged compares
+ // draft-vs-deployed and the banner fires whenever a draft
+ // exists.
+ originalConfig = structuredClone($state.snapshot(getSaveCfg()))
+ if (draftOverlay) loadTriggerConfig(draftOverlay)
if (!defaultConfig) {
initialConfig = structuredClone($state.snapshot(getSaveCfg()))
}
- originalConfig = structuredClone($state.snapshot(getSaveCfg()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load sqs trigger: ${err.body}`, true)
@@ -222,42 +223,28 @@
}
}
+ /** See `NatsTriggerEditorInner.loadTrigger` for the rationale. */
async function loadTrigger(
- defaultConfig?: Record,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Record
+ ): Promise | undefined> {
try {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
- return
- } else {
- const s = await SqsTriggerService.getSqsTrigger({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_sqs',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed at the field
- // level so `loadTriggerConfig` sees the editor's last-saved state.
- const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
- loadTriggerConfig(effective)
+ return undefined
}
+ const s = await SqsTriggerService.getSqsTrigger({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
+ loadTriggerConfig(deployedTrigger)
+ return draftFromBackend
+ ? ({ ...deployedTrigger, ...draftFromBackend } as Record)
+ : undefined
} catch (error) {
sendUserToast(`Could not load SQS trigger: ${error.body}`, true)
+ return undefined
}
}
diff --git a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte
index 0749a7a5f6..50e6c4a9e3 100644
--- a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte
@@ -21,7 +21,6 @@
} from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, emptySchema, emptyString, sendUserToast } from '$lib/utils'
- import { notifyDraftLoaded } from '$lib/userDraftToast'
import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2, X, Plus } from 'lucide-svelte'
@@ -188,11 +187,12 @@
edit = true
dirtyPath = false
dirtyUrl = false
- await loadTrigger(defaultConfig)
+ const draftOverlay = await loadTrigger(defaultConfig)
+ originalConfig = structuredClone($state.snapshot(getSaveCfg()))
+ if (draftOverlay) loadTriggerConfig(draftOverlay)
if (!defaultConfig) {
initialConfig = structuredClone($state.snapshot(getSaveCfg()))
}
- originalConfig = structuredClone($state.snapshot(getSaveCfg()))
await draftSync.maybeRestore()
} catch (err) {
sendUserToast(`Could not load websocket trigger: ${err}`, true)
@@ -303,39 +303,24 @@
}
}
+ /** See `NatsTriggerEditorInner.loadTrigger` for the rationale. */
async function loadTrigger(
- defaultConfig?: Record,
- opts: { getDraft?: boolean } = {}
- ): Promise {
- const getDraft = opts.getDraft ?? true
+ defaultConfig?: Record
+ ): Promise | undefined> {
if (defaultConfig) {
loadTriggerConfig(defaultConfig)
- return
- } else {
- const s = await WebsocketTriggerService.getWebsocketTrigger({
- workspace: $workspaceStore!,
- path: initialPath,
- getDraft
- })
- if (s?.is_draft) {
- notifyDraftLoaded({
- workspace: $workspaceStore!,
- itemKind: 'trigger_websocket',
- path: initialPath,
- draftOnly: s.no_deployed,
- onResetToDeployed: async () => {
- await loadTrigger(undefined, { getDraft: false })
- }
- })
- }
- // Layer the saved draft (if any) over the deployed at the field
- // level so `loadTriggerConfig` sees the editor's last-saved state.
- const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
- const effective = draftFromBackend
- ? { ...deployedTrigger, ...draftFromBackend }
- : deployedTrigger
- loadTriggerConfig(effective)
+ return undefined
}
+ const s = await WebsocketTriggerService.getWebsocketTrigger({
+ workspace: $workspaceStore!,
+ path: initialPath,
+ getDraft: true
+ })
+ const { draft: draftFromBackend, ...deployedTrigger } = (s ?? {}) as any
+ loadTriggerConfig(deployedTrigger)
+ return draftFromBackend
+ ? ({ ...deployedTrigger, ...draftFromBackend } as Record)
+ : undefined
}
let initialMessageRunnableSchemas: Record = $state({})