diff --git a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte index c8e9106943..bea1d1ea33 100644 --- a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte +++ b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte @@ -207,7 +207,7 @@ let { summary = $bindable(), - policy = $bindable(), + policy, diffDrawer = undefined, savedApp = $bindable(undefined), version = $bindable(undefined), @@ -352,8 +352,12 @@ saveDrawerOpen = false } - async function computeTriggerables() { - policy = await updateRawAppPolicy(runnables, policy) + // Returns a copy: `policy` is the editor's own object, which the Deploy panel's + // instant toggles mutate in place. Reassigning it would detach the panel from the + // editor, so later toggles would never reach the preview. After a successful save, + // copy only `triggerables_v2` back so the editor's value matches what was deployed. + function policyWithTriggerables() { + return updateRawAppPolicy(runnables, policy) } async function createApp(path: string) { @@ -364,9 +368,9 @@ if (!policy.execution_mode) { policy.execution_mode = 'publisher' } - await computeTriggerables() try { const { js, css } = await getBundle() + const deployedPolicy = await policyWithTriggerables() await AppService.createAppRaw({ workspace: opWorkspace!, formData: { @@ -374,7 +378,7 @@ value: app, path, summary: summary, - policy, + policy: deployedPolicy, deployment_message: deploymentMsg, custom_path: customPath, preserve_on_behalf_of: preserveOnBehalfOf || undefined, @@ -384,6 +388,7 @@ css } }) + policy.triggerables_v2 = deployedPolicy.triggerables_v2 // New path now exists server-side — drop the autocomplete cache so // it shows up immediately instead of after the 60s TTL. invalidateWorkspacePaths(opWorkspace!) @@ -391,7 +396,7 @@ summary: summary, value: structuredClone(stateSnapshot(app)), path: path, - policy: policy, + policy: deployedPolicy, custom_path: customPath, labels: $state.snapshot(labels) } @@ -589,10 +594,10 @@ return } const { js, css } = await getBundle() - await computeTriggerables() if (!policy.execution_mode) { policy.execution_mode = 'publisher' } + const deployedPolicy = await policyWithTriggerables() const deployed = await AppService.updateAppRaw({ workspace: opWorkspace!, path: appPath!, @@ -600,7 +605,7 @@ app: { value: app!, summary: summary, - policy, + policy: deployedPolicy, path: npath, deployment_message: deploymentMsg, preserve_on_behalf_of: preserveOnBehalfOf || undefined, @@ -614,12 +619,13 @@ css } }) + policy.triggerables_v2 = deployedPolicy.triggerables_v2 invalidateWorkspacePaths(opWorkspace!) savedApp = { summary: summary, value: structuredClone(stateSnapshot(app)), path: npath, - policy, + policy: deployedPolicy, custom_path: customPath, labels: $state.snapshot(labels) } @@ -655,12 +661,13 @@ } async function setPublishState(message?: string) { - await computeTriggerables() + const nextPolicy = await policyWithTriggerables() await AppService.updateApp({ workspace: opWorkspace!, path: appPath, - requestBody: { policy } + requestBody: { policy: nextPolicy } }) + policy.triggerables_v2 = nextPolicy.triggerables_v2 if (message) { sendUserToast(message) } else if (policy.execution_mode == 'anonymous') {