diff --git a/frontend/src/lib/components/copilot/chat/LinkRenderer.svelte b/frontend/src/lib/components/copilot/chat/LinkRenderer.svelte
index 364e7fceaf..adc3fe6184 100644
--- a/frontend/src/lib/components/copilot/chat/LinkRenderer.svelte
+++ b/frontend/src/lib/components/copilot/chat/LinkRenderer.svelte
@@ -34,8 +34,8 @@
title
}: Props = $props()
- // The drawers ride with the docked chat, so a surface can render this pill with nothing
- // able to open one.
+ // The drawers ride with the docked chat and the session tabs with the sessions page, so a
+ // surface can render this pill with nothing able to open one.
const available = $derived.by(() => {
const action = workspaceItemAction(wmKind, wmPath, wmTargetKind, wmRawApp === 'true')
return action && hasToolDisplayActionHandler(action.type) ? action : undefined
@@ -113,8 +113,8 @@
variant="subtle"
iconOnly
startIcon={{ icon: PanelRight }}
- title="Open in drawer"
- aria-label="Open {wmPath} in drawer"
+ title="Open in editor"
+ aria-label="Open {wmPath} in editor"
wrapperClasses="ml-0.5 inline-flex self-center shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"
btnClasses="!w-auto !rounded !p-0.5 !text-tertiary"
onClick={openDrawer}
diff --git a/frontend/src/lib/components/copilot/chat/ToolMessageActions.svelte b/frontend/src/lib/components/copilot/chat/ToolMessageActions.svelte
index db2a0e22c4..84ee04d06f 100644
--- a/frontend/src/lib/components/copilot/chat/ToolMessageActions.svelte
+++ b/frontend/src/lib/components/copilot/chat/ToolMessageActions.svelte
@@ -125,8 +125,9 @@
{card.title}
{card.subtitle}
-
+
{#if hasToolDisplayActionHandler(action.type)}
{
it('maps a non-item mutation to its own list page only', () => {
@@ -52,6 +53,26 @@ describe('toolReloadEffect', () => {
})
})
+describe('page item tabs', () => {
+ const tab = (url: string): SessionPreviewTab => ({ id: url, url, loc: url })
+ const kafkaA = tab('pageitem:trigger.kafka/u%2Fme%2Fa')
+ const kafkaB = tab('pageitem:trigger.kafka/u%2Fme%2Fb')
+ const list = tab('/kafka_triggers')
+
+ it('reloads only the trigger a write names, and its list page', () => {
+ const { pages, items } = toolReloadEffect('write_trigger', {
+ kind: 'kafka',
+ config: { path: 'u/me/a' }
+ })
+ const named = new Set(items.map((i) => pageItemUrl(i)))
+ expect(tabsToReload([kafkaA, kafkaB, list], new Set(pages), named)).toEqual([kafkaA, list])
+ })
+
+ it('reloads every tab of the kind when the tool names no item', () => {
+ expect(tabsToReload([kafkaA, kafkaB], new Set(['/kafka_triggers']))).toEqual([kafkaA, kafkaB])
+ })
+})
+
describe('tabsToReload', () => {
const scheduleTab: SessionPreviewTab = { id: 's', url: '/schedules', loc: '/schedules' }
const resourceTab: SessionPreviewTab = { id: 'r', url: '/resources', loc: '/resources' }
diff --git a/frontend/src/lib/components/sessions/previewReload.ts b/frontend/src/lib/components/sessions/previewReload.ts
index 1c1fcc3075..bdfbeaa3ff 100644
--- a/frontend/src/lib/components/sessions/previewReload.ts
+++ b/frontend/src/lib/components/sessions/previewReload.ts
@@ -34,7 +34,8 @@ export function toolReloadEffect(name: string, args: any): ToolReloadEffect {
case 'write_schedule':
return withItem(['/schedules'], itemRef('schedule', args))
case 'write_trigger':
- return withItem(triggerPages(args?.kind), itemRef('trigger', args, args?.kind))
+ // Its path sits in the trigger's own config, not beside `kind`.
+ return withItem(triggerPages(args?.kind), itemRef('trigger', args?.config, args?.kind))
case 'write_resource':
return withItem(['/resources'], itemRef('resource', args))
case 'write_variable':
diff --git a/frontend/src/lib/components/triggers/amqp/AmqpTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/amqp/AmqpTriggerEditorInner.svelte
index 31d8cd0ac3..504d367b24 100644
--- a/frontend/src/lib/components/triggers/amqp/AmqpTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/amqp/AmqpTriggerEditorInner.svelte
@@ -234,6 +234,8 @@
}
async function loadTriggerConfig(cfg?: Record): Promise {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
try {
amqp_resource_path = cfg?.amqp_resource_path
queue_name = cfg?.queue_name ?? ''
diff --git a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte
index 38412ef3b8..4ec009dff4 100644
--- a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte
@@ -232,6 +232,8 @@
}
async function loadTriggerConfig(cfg?: Record): Promise {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
script_path = cfg?.script_path
initialScriptPath = cfg?.script_path
azure_resource_path = cfg?.azure_resource_path
@@ -257,13 +259,7 @@
const previousPath = initialPath
const cfg = azureConfig
if (!cfg) return
- const isSaved = await saveAzureTriggerFromCfg(
- initialPath,
- cfg,
- edit,
- wsId!,
- usedTriggerKinds
- )
+ const isSaved = await saveAzureTriggerFromCfg(initialPath, cfg, edit, wsId!, usedTriggerKinds)
if (isSaved) {
draftSync.discard(previousPath, getAzureConfig())
onUpdate?.(cfg.path)
diff --git a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte
index f8426e7529..df9969daaa 100644
--- a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte
@@ -209,6 +209,8 @@
}
function loadTriggerConfig(cfg?: Partial): void {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
script_path = cfg?.script_path ?? ''
initialScriptPath = cfg?.script_path ?? ''
is_flow = cfg?.is_flow ?? false
diff --git a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte
index 92bd67bddb..b600c574cf 100644
--- a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte
@@ -259,6 +259,8 @@
}
async function loadTriggerConfig(cfg?: Record): Promise {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
script_path = cfg?.script_path
initialScriptPath = cfg?.script_path
gcp_resource_path = cfg?.gcp_resource_path ?? undefined
diff --git a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte
index 279460f614..d648406f01 100644
--- a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte
@@ -352,6 +352,8 @@
}
function loadTriggerConfig(cfg?: Partial): void {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
script_path = cfg?.script_path ?? ''
initialScriptPath = cfg?.script_path ?? ''
is_flow = cfg?.is_flow ?? false
diff --git a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte
index e20cb95d16..fb497c1626 100644
--- a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte
@@ -241,6 +241,8 @@
}
function loadTriggerConfig(cfg?: Record): void {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
script_path = cfg?.script_path
initialScriptPath = cfg?.script_path
is_flow = cfg?.is_flow
diff --git a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte
index d6b32dbab2..b72b1da8ce 100644
--- a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte
@@ -237,6 +237,8 @@
}
async function loadTriggerConfig(cfg?: Record): Promise {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
try {
mqtt_resource_path = cfg?.mqtt_resource_path
subscribe_topics = cfg?.subscribe_topics
diff --git a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte
index 5b6bc14f36..80612377a0 100644
--- a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte
@@ -230,6 +230,8 @@
}
async function loadTriggerConfig(cfg?: Record): Promise {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
script_path = cfg?.script_path
initialScriptPath = cfg?.script_path
is_flow = cfg?.is_flow
diff --git a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte
index a36474b310..3286ebc47e 100644
--- a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte
@@ -366,6 +366,8 @@
}
async function loadTriggerConfig(cfg?: Record): Promise {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
script_path = cfg?.script_path
initialScriptPath = cfg?.script_path
is_flow = cfg?.is_flow
diff --git a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte
index db101636ff..d20bc35fee 100644
--- a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte
@@ -219,6 +219,8 @@
}
async function loadTriggerConfig(cfg?: Record): Promise {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
try {
script_path = cfg?.script_path
initialScriptPath = cfg?.script_path
diff --git a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte
index 9f30250e06..b36e6da9ad 100644
--- a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte
@@ -264,6 +264,8 @@
}
function loadTriggerConfig(cfg?: Record): void {
+ // The loaded trigger says what it runs; an opener's `isFlow` is only its guess.
+ if (cfg?.is_flow !== undefined) itemKind = cfg.is_flow ? 'flow' : 'script'
script_path = cfg?.script_path
initialScriptPath = cfg?.script_path
is_flow = cfg?.is_flow