From a4eb80bd8d492ecb2b999fb46b3f6414ee1638cb Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Thu, 17 Sep 2026 17:05:15 +0200 Subject: [PATCH] fix: guard every component under a session editor against the navigation workspace Co-Authored-By: Claude Opus 5 (1M context) --- .../lib/components/AIAgentLogViewer.svelte | 89 +++++++------- .../src/lib/components/ApiConnectForm.svelte | 6 +- .../src/lib/components/AppConnectInner.svelte | 7 +- frontend/src/lib/components/ArgInfo.svelte | 8 +- .../components/BedrockCredentialsCheck.svelte | 12 +- frontend/src/lib/components/CliHelpBox.svelte | 6 +- .../lib/components/DBManagerContent.svelte | 12 +- frontend/src/lib/components/DBTable.svelte | 14 ++- .../src/lib/components/DatatablePicker.svelte | 6 +- .../lib/components/DefaultScriptsInner.svelte | 7 +- .../src/lib/components/DucklakePicker.svelte | 12 +- frontend/src/lib/components/Editor.svelte | 22 ++-- frontend/src/lib/components/EditorBar.svelte | 11 +- .../src/lib/components/EditorHeader.svelte | 12 +- .../components/ErrorOrRecoveryHandler.svelte | 9 +- .../src/lib/components/FlowBuilder.svelte | 15 +-- .../src/lib/components/FlowGraphViewer.svelte | 6 +- .../lib/components/FlowGraphViewerStep.svelte | 7 +- .../components/FlowHistoryJobPicker.svelte | 8 +- .../src/lib/components/FlowLogViewer.svelte | 6 +- .../FlowLoopIterationPreview.svelte | 6 +- .../lib/components/FlowPreviewContent.svelte | 6 +- .../lib/components/FlowRestartButton.svelte | 8 +- .../lib/components/FlowStatusViewer.svelte | 7 +- .../components/FlowStatusViewerInner.svelte | 20 ++-- frontend/src/lib/components/FlowViewer.svelte | 6 +- .../src/lib/components/FolderEditor.svelte | 34 +++--- .../src/lib/components/FolderPicker.svelte | 10 +- .../components/GitRepoPopoverPicker.svelte | 10 +- .../src/lib/components/GitRepoViewer.svelte | 6 +- .../src/lib/components/GroupEditor.svelte | 21 ++-- .../src/lib/components/HistoricList.svelte | 14 ++- frontend/src/lib/components/JobLoader.svelte | 6 +- .../src/lib/components/JobOtelTraces.svelte | 43 ++++--- frontend/src/lib/components/LogViewer.svelte | 10 +- .../lib/components/ModulePreviewForm.svelte | 6 +- frontend/src/lib/components/ModuleTest.svelte | 6 +- .../components/ParqetCsvTableRenderer.svelte | 9 +- frontend/src/lib/components/Path.svelte | 30 +++-- .../lib/components/PermissionHistory.svelte | 14 ++- .../src/lib/components/QueuePosition.svelte | 6 +- .../lib/components/ResourceTypePicker.svelte | 8 +- .../src/lib/components/ScriptBuilder.svelte | 4 +- .../src/lib/components/ScriptEditor.svelte | 13 +- .../src/lib/components/ScriptPicker.svelte | 7 +- .../components/ScriptVersionHistory.svelte | 8 +- frontend/src/lib/components/SqlRepl.svelte | 6 +- .../lib/components/SummaryPathDisplay.svelte | 13 +- .../src/lib/components/WorkerTagPicker.svelte | 12 +- .../src/lib/components/WorkerTagSelect.svelte | 14 ++- .../lib/components/WorkflowTimeline.svelte | 11 +- .../WorkspaceItemDrillPicker.svelte | 11 +- .../lib/components/aiEvals/EvalsPane.svelte | 6 +- .../apps/editor/AppEditorHeaderDeploy.svelte | 13 +- .../apps/editor/AppJobsDrawer.svelte | 12 +- .../apps/editor/DeploymentHistory.svelte | 14 ++- .../InlineScriptRunnableByPath.svelte | 12 +- .../mainInput/RunnableSelector.svelte | 13 +- .../mainInput/WorkspaceFlowList.svelte | 6 +- .../mainInput/WorkspaceScriptList.svelte | 6 +- .../assets/AssetGraph/AssetNode.svelte | 15 ++- .../assets/AssetGraph/AssetRunsPanel.svelte | 18 +-- .../assets/AssetGraph/DataTablePreview.svelte | 14 ++- .../AssetGraph/DucklakeResultPreview.svelte | 12 +- .../AssetGraph/DucklakeVersionPreview.svelte | 13 +- .../AssetGraph/PipelineScriptView.svelte | 6 +- .../AssetGraph/PipelineTriggerEditors.svelte | 6 +- .../assets/AssetGraph/RunnableNode.svelte | 6 +- .../assets/AssetsDropdownButton.svelte | 10 +- .../components/assets/JobAssetsViewer.svelte | 16 +-- .../common/fileDownload/FileDownload.svelte | 6 +- .../common/fileUpload/FileUpload.svelte | 16 +-- .../components/copilot/StepGenQuick.svelte | 6 +- .../copilot/chat/AIChatMessage.svelte | 8 +- .../copilot/chat/AIChatModelSettings.svelte | 10 +- .../chat/AssistantSettingsModal.svelte | 6 +- .../copilot/chat/ChatContextPicker.svelte | 6 +- .../chat/DatatableCreationPolicy.svelte | 6 +- .../src/lib/components/dbt/DbtEditor.svelte | 6 +- .../details/ErrorHandlerToggleButtonV2.svelte | 10 +- .../components/flows/FlowAssetsHandler.svelte | 6 +- .../lib/components/flows/FlowEditor.svelte | 9 +- .../components/flows/FlowHistoryInner.svelte | 6 +- .../flows/common/FlowCardHeader.svelte | 7 +- .../flows/content/AgentEditorModal.svelte | 6 +- .../flows/content/AgentResourceBar.svelte | 8 +- .../flows/content/AiAgentStepInputs.svelte | 6 +- .../flows/content/ExpandedSubflowStep.svelte | 6 +- .../flows/content/FlowEditorDrawer.svelte | 6 +- .../content/FlowEnvironmentVariables.svelte | 6 +- .../components/flows/content/FlowInput.svelte | 6 +- .../flows/content/FlowInputsFlow.svelte | 6 +- .../flows/content/FlowInputsQuick.svelte | 17 ++- .../flows/content/FlowModuleComponent.svelte | 6 +- .../flows/content/FlowModuleScript.svelte | 6 +- .../flows/content/FlowModuleSuspend.svelte | 9 +- .../content/FlowModuleWorkerTagSelect.svelte | 4 +- .../flows/content/FlowPathViewer.svelte | 8 +- .../flows/content/FlowSettings.svelte | 7 +- .../flows/content/McpToolEditor.svelte | 5 +- .../flows/content/ScriptEditorDrawer.svelte | 6 +- .../WorkspaceScriptSettingsDrawer.svelte | 6 +- .../flows/conversations/FlowChat.svelte | 7 +- .../flows/map/FlowModuleSchemaMap.svelte | 6 +- .../flows/map/InsertModuleInner.svelte | 6 +- .../flows/pickers/PickHubScript.svelte | 7 +- .../flows/pickers/PickHubScriptQuick.svelte | 7 +- .../pickers/WorkspaceScriptPicker.svelte | 10 +- .../pickers/WorkspaceScriptPickerQuick.svelte | 11 +- .../flows/propPicker/StepHistory.svelte | 6 +- .../lib/components/graph/FlowGraphV2.svelte | 6 +- .../jobs/MissingWorkerTagAlert.svelte | 6 +- .../components/metrics/MetricsDrawer.svelte | 6 +- .../components/operatingWorkspace.svelte.ts | 8 ++ .../lib/components/operatingWorkspace.test.ts | 113 ++++++++++-------- .../propertyPicker/ObjectViewer.svelte | 14 +-- .../propertyPicker/PropPicker.svelte | 8 +- .../components/raw_apps/RawAppEditor.svelte | 8 +- .../raw_apps/RawAppEditorHeader.svelte | 19 +-- .../components/runs/JobDetailHeader.svelte | 17 +-- .../runs/NoWorkerWithTagWarning.svelte | 6 +- .../src/lib/components/runs/RunBadges.svelte | 6 +- .../components/schema/JobSchemaPicker.svelte | 6 +- .../schema/RunningJobSchemaPicker.svelte | 62 +++++----- .../components/scriptEditor/LogPanel.svelte | 12 +- .../components/settings/CreateToken.svelte | 13 +- .../settings/EditTokenScopesModal.svelte | 6 +- .../azure/AzureTriggerEditorInner.svelte | 10 +- .../email/EmailTriggerEditorInner.svelte | 10 +- .../triggers/gcp/GcpTriggerEditorInner.svelte | 10 +- .../triggers/http/RouteCorsOption.svelte | 4 +- .../triggers/http/RouteEditorInner.svelte | 24 ++-- .../kafka/KafkaTriggerEditorInner.svelte | 10 +- .../mqtt/MqttTriggerEditorInner.svelte | 10 +- .../nats/NatsTriggerEditorInner.svelte | 10 +- .../PostgresTriggerEditorInner.svelte | 8 +- .../triggers/sqs/SqsTriggerEditorInner.svelte | 10 +- .../websocket/WebsocketCapture.svelte | 26 ++-- .../WebsocketTriggerEditorInner.svelte | 10 +- .../lib/components/wizards/AppPicker.svelte | 29 +++-- 140 files changed, 988 insertions(+), 649 deletions(-) diff --git a/frontend/src/lib/components/AIAgentLogViewer.svelte b/frontend/src/lib/components/AIAgentLogViewer.svelte index 2549fbb29f..e92ea4b3cb 100644 --- a/frontend/src/lib/components/AIAgentLogViewer.svelte +++ b/frontend/src/lib/components/AIAgentLogViewer.svelte @@ -7,11 +7,13 @@ type FlowStatusModule, type Job } from '$lib/gen' - import { workspaceStore } from '$lib/stores' import FlowLogViewerWrapper from './FlowLogViewerWrapper.svelte' import { z } from 'zod' import { untrack } from 'svelte' import type { AgentTool } from './flows/agentToolUtils' + import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte' + + const operatingWorkspace = useOperatingWorkspace() type AgentActionWithContent = NonNullable[number] & { content?: unknown @@ -81,7 +83,7 @@ if (!job || job.type !== 'CompletedJob') { job = await JobService.getJob({ id: toolCall.job_id, - workspace: workspaceId ?? $workspaceStore! + workspace: workspaceId ?? $operatingWorkspace! }) } states[idx.toString()] = { @@ -186,50 +188,49 @@ job = { ...agentJob, raw_flow: { - modules: agentActions - .map((toolCall, idx) => { - if (toolCall.type === 'message') { - return { - id: idx.toString(), - value: { - type: 'identity' as const - } + modules: agentActions.map((toolCall, idx) => { + if (toolCall.type === 'message') { + return { + id: idx.toString(), + value: { + type: 'identity' as const } - } else if (toolCall.type === 'mcp_tool_call') { - return { - id: idx.toString(), - value: { - type: 'identity' as const - }, - summary: toolCall.function_name, - arguments: toolCall.arguments - } - } else if (toolCall.type === 'web_search') { - return { - id: idx.toString(), - value: { - type: 'identity' as const - }, - summary: 'Web Search' - } - } else { - const module = tools.find((m) => m.summary === toolCall.function_name) - // A definition can be missing for a call that did run: the tool was renamed or - // removed since, or it belongs to a linked agent whose resource is no longer - // readable. Keep the recorded call — its args, logs and result come from the - // child job — rather than dropping it from the history. - return module - ? ({ - ...module, - id: idx.toString() - } as FlowModule) - : ({ - id: idx.toString(), - value: { type: 'identity' as const }, - summary: toolCall.function_name - } as FlowModule) } - }) + } else if (toolCall.type === 'mcp_tool_call') { + return { + id: idx.toString(), + value: { + type: 'identity' as const + }, + summary: toolCall.function_name, + arguments: toolCall.arguments + } + } else if (toolCall.type === 'web_search') { + return { + id: idx.toString(), + value: { + type: 'identity' as const + }, + summary: 'Web Search' + } + } else { + const module = tools.find((m) => m.summary === toolCall.function_name) + // A definition can be missing for a call that did run: the tool was renamed or + // removed since, or it belongs to a linked agent whose resource is no longer + // readable. Keep the recorded call — its args, logs and result come from the + // child job — rather than dropping it from the history. + return module + ? ({ + ...module, + id: idx.toString() + } as FlowModule) + : ({ + id: idx.toString(), + value: { type: 'identity' as const }, + summary: toolCall.function_name + } as FlowModule) + } + }) } } } diff --git a/frontend/src/lib/components/ApiConnectForm.svelte b/frontend/src/lib/components/ApiConnectForm.svelte index dedeee90e2..2255817c5e 100644 --- a/frontend/src/lib/components/ApiConnectForm.svelte +++ b/frontend/src/lib/components/ApiConnectForm.svelte @@ -1,7 +1,6 @@ @@ -20,7 +22,7 @@ Setup the wmill cli for this workspace & remote:
diff --git a/frontend/src/lib/components/DBManagerContent.svelte b/frontend/src/lib/components/DBManagerContent.svelte index b0ef2859df..3ee98538ba 100644 --- a/frontend/src/lib/components/DBManagerContent.svelte +++ b/frontend/src/lib/components/DBManagerContent.svelte @@ -1,5 +1,5 @@
@@ -46,9 +47,6 @@ {onClear} /> {#if showSchemaExplorer && value && assetCanBeExplored({ kind: 'ducklake', path: value })} - + {/if}
diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index 987aa937eb..6aabc30c2b 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -42,7 +42,6 @@ import { editorConfig, registerWebviewPaste, updateOptions } from '$lib/editorUtils' import { editorFontSize } from '$lib/editorFontSize.svelte' import { createHash as randomHash } from '$lib/editorLangUtils' - import { workspaceStore } from '$lib/stores' import DdlMigrationGuard from './DdlMigrationGuard.svelte' import { type Preview, @@ -120,6 +119,9 @@ import { rawAppLintStore, type MonacoLintError } from './raw_apps/lintStore' import { MarkerSeverity } from 'monaco-editor' import { resource, useDebounce, watch } from 'runed' + import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte' + + const operatingWorkspace = useOperatingWorkspace() // import EditorTheme from './EditorTheme.svelte' let divEl: HTMLDivElement | null = $state(null) @@ -684,7 +686,7 @@ // via a short-TTL cache — macros are late-bound, so mild staleness is fine. async function addWorkspaceMacroCompletions() { workspaceMacroCompletor?.dispose() - const workspace = $workspaceStore + const workspace = $operatingWorkspace if (!workspace) return let macros: Awaited> = [] try { @@ -739,7 +741,7 @@ provideCompletionItems: async function (model, position) { // Read the store per request, not at registration — the provider // outlives a workspace switch. - const workspace = $workspaceStore + const workspace = $operatingWorkspace if (!workspace) return { suggestions: [] } const before = model.getLineContent(position.lineNumber).slice(0, position.column - 1) if (!/^\s*(\/\/|--|#)\s*(column|data_test|on|materialize)\b/.test(before)) { @@ -780,7 +782,7 @@ $dbSchemas[resourcePath] = await getDbSchemas( lang === 'graphql' ? 'graphql' : (scriptLang ?? ''), resourcePath, - $workspaceStore, + $operatingWorkspace, (e) => console.error(`error getting ${lang} (${scriptLang}) db schema`, e), { customTag } ) @@ -1778,9 +1780,9 @@ let customTsTypesData = resource([() => lang], async () => { if (lang !== 'typescript') return undefined let datatables = ( - await WorkspaceService.listDataTables({ workspace: $workspaceStore ?? '' }) + await WorkspaceService.listDataTables({ workspace: $operatingWorkspace ?? '' }) ).map((d) => d.name) - let ducklakes = await WorkspaceService.listDucklakes({ workspace: $workspaceStore ?? '' }) + let ducklakes = await WorkspaceService.listDucklakes({ workspace: $operatingWorkspace ?? '' }) return { datatables, ducklakes } }) function setTypescriptCustomTypes() { @@ -1822,7 +1824,7 @@ scriptLang === 'nativets') ) { const resourceTypes = await ResourceService.listResourceType({ - workspace: $workspaceStore ?? '' + workspace: $operatingWorkspace ?? '' }) const namespace = formatResourceTypes( @@ -2023,7 +2025,7 @@ $lspTokenStore = newToken token = newToken } - let root = hostname + '/api/scripts_u/tokened_raw/' + $workspaceStore + '/' + token + let root = hostname + '/api/scripts_u/tokened_raw/' + $operatingWorkspace + '/' + token return root } @@ -2274,10 +2276,10 @@ -{#if datatableForMigrations && $workspaceStore} +{#if datatableForMigrations && $operatingWorkspace} {/if} diff --git a/frontend/src/lib/components/EditorBar.svelte b/frontend/src/lib/components/EditorBar.svelte index 91516843ab..81ef6c1c96 100644 --- a/frontend/src/lib/components/EditorBar.svelte +++ b/frontend/src/lib/components/EditorBar.svelte @@ -22,7 +22,6 @@ diff --git a/frontend/src/lib/components/FlowHistoryJobPicker.svelte b/frontend/src/lib/components/FlowHistoryJobPicker.svelte index 26fa41f1af..dfb4927af1 100644 --- a/frontend/src/lib/components/FlowHistoryJobPicker.svelte +++ b/frontend/src/lib/components/FlowHistoryJobPicker.svelte @@ -3,9 +3,11 @@ import { createEventDispatcher, untrack } from 'svelte' import PopoverV2 from '$lib/components/meltComponents/Popover.svelte' import HistoricInputs from './HistoricInputs.svelte' - import { workspaceStore } from '$lib/stores' import { JobService } from '$lib/gen' import { Button } from './common' + import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte' + + const operatingWorkspace = useOperatingWorkspace() interface Props { path: string @@ -27,7 +29,7 @@ async function loadInitial() { loading = true let jobs = await JobService.listJobs({ - workspace: $workspaceStore!, + workspace: $operatingWorkspace!, scriptPathExact: path, jobKinds: ['flow', 'flowpreview'].join(','), perPage: 1 @@ -43,7 +45,7 @@ } $effect(() => { - if ($workspaceStore && !newFlow) { + if ($operatingWorkspace && !newFlow) { untrack(() => loadInitial()) } }) diff --git a/frontend/src/lib/components/FlowLogViewer.svelte b/frontend/src/lib/components/FlowLogViewer.svelte index 385d028e7e..f4974c7de5 100644 --- a/frontend/src/lib/components/FlowLogViewer.svelte +++ b/frontend/src/lib/components/FlowLogViewer.svelte @@ -11,7 +11,6 @@ Keyboard } from 'lucide-svelte' import { base } from '$lib/base' - import { workspaceStore } from '$lib/stores' import ObjectViewer from './propertyPicker/ObjectViewer.svelte' import LogViewer from './LogViewer.svelte' import FlowLogViewer from './FlowLogViewer.svelte' @@ -26,6 +25,9 @@ import { Tooltip } from './meltComponents' import FlowTimelineBar from './FlowTimelineBar.svelte' import { getActiveReplay } from './recording/replay.svelte' + import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte' + + const operatingWorkspace = useOperatingWorkspace() type RootJobData = Partial @@ -98,7 +100,7 @@ function getJobLink(jobId: string | undefined): string { if (!jobId) return '' - return `${base}/run/${jobId}?workspace=${workspaceId ?? $workspaceStore}` + return `${base}/run/${jobId}?workspace=${workspaceId ?? $operatingWorkspace}` } function getStatusColor(status: FlowStatusModule['type'] | undefined): string { diff --git a/frontend/src/lib/components/FlowLoopIterationPreview.svelte b/frontend/src/lib/components/FlowLoopIterationPreview.svelte index 0a4f5c60ee..f136cbfe39 100644 --- a/frontend/src/lib/components/FlowLoopIterationPreview.svelte +++ b/frontend/src/lib/components/FlowLoopIterationPreview.svelte @@ -1,6 +1,5 @@ diff --git a/frontend/src/lib/components/JobLoader.svelte b/frontend/src/lib/components/JobLoader.svelte index 71bd2fbb51..324bdea6c7 100644 --- a/frontend/src/lib/components/JobLoader.svelte +++ b/frontend/src/lib/components/JobLoader.svelte @@ -14,7 +14,6 @@ type WorkflowStatus, type OpenFlow } from '$lib/gen' - import { workspaceStore } from '$lib/stores' import { getViewToken } from '$lib/viewToken' import { WM_LOGS_SKIPPED } from '$lib/consts' import { getContext, onDestroy, tick, untrack } from 'svelte' @@ -22,6 +21,9 @@ import { sendUserToast } from '$lib/toast' import { DynamicInput, isScriptPreview } from '$lib/utils' import { getActiveReplay, getReplayStartTime } from './recording/replay.svelte' + import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte' + + const operatingWorkspace = useOperatingWorkspace() // Will be set to number if job is not a flow @@ -75,7 +77,7 @@ children }: Props = $props() - let workspace = $derived(workspaceOverride ?? $workspaceStore) + let workspace = $derived(workspaceOverride ?? $operatingWorkspace) let syncIteration: number = 0 let errorIteration = 0 diff --git a/frontend/src/lib/components/JobOtelTraces.svelte b/frontend/src/lib/components/JobOtelTraces.svelte index d57a7158e1..9332abdff1 100644 --- a/frontend/src/lib/components/JobOtelTraces.svelte +++ b/frontend/src/lib/components/JobOtelTraces.svelte @@ -1,9 +1,11 @@