From d31d298130ea05392ea344333ce44964c52875f3 Mon Sep 17 00:00:00 2001 From: tristantr Date: Mon, 13 Jul 2026 12:17:59 +0200 Subject: [PATCH] fix(hub-projects): retarget plain trigger resource paths on import Co-Authored-By: Claude Fable 5 --- .../workspaceSettings/projectBundle.test.ts | 33 +++++++++++++++++++ .../workspaceSettings/projectBundle.ts | 18 ++++++++++ .../(logged)/projects/install/+page.svelte | 8 +++-- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/components/workspaceSettings/projectBundle.test.ts b/frontend/src/lib/components/workspaceSettings/projectBundle.test.ts index b10f84ed8f..5ecf1ed86c 100644 --- a/frontend/src/lib/components/workspaceSettings/projectBundle.test.ts +++ b/frontend/src/lib/components/workspaceSettings/projectBundle.test.ts @@ -6,6 +6,7 @@ import { extractAppRefs, buildPathMap, rewriteContent, + rewriteTriggerConfig, rewriteFlowValue, rewriteAppValue, extractRawAppRefs, @@ -142,6 +143,38 @@ describe('rewriteContent', () => { }) }) +describe('rewriteTriggerConfig', () => { + const map = new Map([ + ['f/proj/kafka', 'f/target/kafka'], + ['f/proj/script', 'f/target/script'] + ]) + it('remaps plain resource path fields', () => { + expect( + rewriteTriggerConfig({ kafka_resource_path: 'f/proj/kafka', group_id: 'g1' }, map) + ).toEqual({ kafka_resource_path: 'f/target/kafka', group_id: 'g1' }) + }) + it('remaps nested objects, arrays, and $res: tokens', () => { + expect( + rewriteTriggerConfig( + { + nested: { path: 'f/proj/script' }, + list: ['f/proj/kafka', 'unrelated'], + code: 'x = "$res:f/proj/kafka"' + }, + map + ) + ).toEqual({ + nested: { path: 'f/target/script' }, + list: ['f/target/kafka', 'unrelated'], + code: 'x = "$res:f/target/kafka"' + }) + }) + it('leaves non-matching strings and non-string values untouched', () => { + const config = { url: 'wss://example.com', port: 9092, enabled: true, extra: null } + expect(rewriteTriggerConfig(config, map)).toEqual(config) + }) +}) + describe('rewriteFlowValue', () => { it('rewrites inline code, static inputs, and script paths; clones input', () => { const map = new Map([ diff --git a/frontend/src/lib/components/workspaceSettings/projectBundle.ts b/frontend/src/lib/components/workspaceSettings/projectBundle.ts index 2ead24390b..dd8ca5f15d 100644 --- a/frontend/src/lib/components/workspaceSettings/projectBundle.ts +++ b/frontend/src/lib/components/workspaceSettings/projectBundle.ts @@ -155,6 +155,24 @@ export function rewriteContent(content: string, map: Map): strin }) } +/** + * Trigger configs reference resources as plain path strings (e.g. + * `kafka_resource_path: "f/slug/db"`), not `$res:` tokens, so token rewriting + * misses them. Deep-walk the config and remap any string that exact-matches a + * map key (map keys are full bundle paths, so an exact match is a reference), + * falling back to `$res:` token rewriting for embedded refs. + */ +export function rewriteTriggerConfig(config: any, map: Map): any { + if (typeof config === 'string') return map.get(config) ?? rewriteContent(config, map) + if (Array.isArray(config)) return config.map((v) => rewriteTriggerConfig(v, map)) + if (config && typeof config === 'object') { + return Object.fromEntries( + Object.entries(config).map(([k, v]) => [k, rewriteTriggerConfig(v, map)]) + ) + } + return config +} + export function rewriteFlowValue(value: any, map: Map): any { const cloned = JSON.parse(JSON.stringify(value ?? {})) for (const mod of getAllModules(cloned?.modules ?? [], cloned?.failure_module)) { diff --git a/frontend/src/routes/(root)/(logged)/projects/install/+page.svelte b/frontend/src/routes/(root)/(logged)/projects/install/+page.svelte index 90201fd28c..66da1d6968 100644 --- a/frontend/src/routes/(root)/(logged)/projects/install/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/projects/install/+page.svelte @@ -29,7 +29,8 @@ rewriteAppValue, rewriteContent, rewriteFlowValue, - rewriteRawAppContent + rewriteRawAppContent, + rewriteTriggerConfig } from '$lib/components/workspaceSettings/projectBundle' import { updatePolicy } from '$lib/components/apps/editor/appPolicy' import { updateRawAppPolicy } from '$lib/sharedUtils' @@ -275,8 +276,9 @@ ...t, path: remap(t.path), runnable_path: remap(t.runnable_path), - // `$res:` refs can live in trigger args/config. - config: t.config ? JSON.parse(rewriteContent(JSON.stringify(t.config), map)) : t.config + // Configs hold both `$res:` tokens and plain resource paths + // (kafka_resource_path etc.) — rewrite both. + config: t.config ? rewriteTriggerConfig(t.config, map) : t.config })) } }