diff --git a/src/libswamp/data/search.ts b/src/libswamp/data/search.ts index 4f0fc53d..abe7f706 100644 --- a/src/libswamp/data/search.ts +++ b/src/libswamp/data/search.ts @@ -43,6 +43,7 @@ export interface DataSearchItem { createdAt: string; tags: Record; workflowTag?: string; + jobTag?: string; stepTag?: string; } @@ -303,6 +304,7 @@ export async function* dataSearch( createdAt: data.createdAt.toISOString(), tags: data.tags, workflowTag: data.tags.workflow, + jobTag: data.tags.job, stepTag: data.tags.step, }); } diff --git a/src/libswamp/data/search_test.ts b/src/libswamp/data/search_test.ts index cb8e82c2..720018a5 100644 --- a/src/libswamp/data/search_test.ts +++ b/src/libswamp/data/search_test.ts @@ -158,6 +158,45 @@ Deno.test("dataSearch: filters by tags with AND logic", async () => { assertEquals(completed.data.results[0].id, "d1"); }); +Deno.test("dataSearch: surfaces workflowTag/jobTag/stepTag from data tags", async () => { + const items = [ + makeDataItem({ + id: "d1", + tags: { workflow: "my-wf", job: "my-job", step: "my-step" }, + }), + ]; + const deps = makeDeps(items); + const events = await collect( + dataSearch(createLibSwampContext(), deps, {}), + ); + + const completed = events[1] as Extract< + DataSearchEvent, + { kind: "completed" } + >; + assertEquals(completed.data.results.length, 1); + assertEquals(completed.data.results[0].workflowTag, "my-wf"); + assertEquals(completed.data.results[0].jobTag, "my-job"); + assertEquals(completed.data.results[0].stepTag, "my-step"); +}); + +Deno.test("dataSearch: jobTag is undefined when data has no job tag", async () => { + const items = [ + makeDataItem({ id: "d1", tags: {} }), + ]; + const deps = makeDeps(items); + const events = await collect( + dataSearch(createLibSwampContext(), deps, {}), + ); + + const completed = events[1] as Extract< + DataSearchEvent, + { kind: "completed" } + >; + assertEquals(completed.data.results.length, 1); + assertEquals(completed.data.results[0].jobTag, undefined); +}); + Deno.test("dataSearch: yields error when model not found", async () => { const deps = makeDeps([], { findDefinitionByIdOrName: () => Promise.resolve(null), diff --git a/src/presentation/renderers/data_search.tsx b/src/presentation/renderers/data_search.tsx index 6d30bcd9..5c61fbd7 100644 --- a/src/presentation/renderers/data_search.tsx +++ b/src/presentation/renderers/data_search.tsx @@ -122,7 +122,7 @@ class InkDataSearchRenderer implements DataSearchRenderer { (item) => `${item.name} ${item.modelName} ${item.modelType} ${item.type} ${ item.workflowTag ?? "" - } ${item.stepTag ?? ""} ${ + } ${item.jobTag ?? ""} ${item.stepTag ?? ""} ${ Object.entries(item.tags).map(([k, v]) => `${k}=${v}`).join(" ") }`, renderDataResultLine, @@ -179,6 +179,7 @@ function buildMetadataMarkdown(item: DataSearchItem): string { ]; if (item.workflowTag) lines.push(`**Workflow:** ${item.workflowTag}`); + if (item.jobTag) lines.push(`**Job:** ${item.jobTag}`); if (item.stepTag) lines.push(`**Step:** ${item.stepTag}`); if (tagEntries.length > 0) {