From cf8c0e4257838ff2db329d9d48a3eb4d5c671f50 Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Wed, 30 Sep 2026 19:05:42 +0200 Subject: [PATCH] feat: assets-only nodes name their script in a header tab instead of a side chip Co-Authored-By: Claude Opus 5.5 (1M context) --- .../assets/AssetGraph/AssetGraphCanvas.svelte | 27 +++- .../assets/AssetGraph/AssetNode.svelte | 146 +++++++++--------- .../assets/AssetGraph/PipelineNodeCard.svelte | 23 ++- .../assets/AssetGraph/assetGraphLayout.ts | 2 + .../assets/AssetGraph/assetNodeWidth.ts | 33 ++-- 5 files changed, 132 insertions(+), 99 deletions(-) diff --git a/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte b/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte index dd47a1f5c9..388c8fae30 100644 --- a/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte +++ b/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte @@ -22,7 +22,11 @@ import AssetGraphEdge from './AssetGraphEdge.svelte' import PanToNode from './PanToNode.svelte' import InitialFitView from './InitialFitView.svelte' - import { layoutAssetGraph, PIPELINE_NODE_EXTRA_ROW } from './assetGraphLayout' + import { + layoutAssetGraph, + PIPELINE_NODE_EXTRA_ROW, + PIPELINE_NODE_HEADER + } from './assetGraphLayout' import { assetsOnlyView, upstreamDeletion, @@ -1430,12 +1434,17 @@ : `${upstream.trigger.label}${upstream.trigger.draft ? ' · draft' : ''}`, runState: 'runState' in upstream && !!upstream.runState, chipIcon: foldedErrors > 0, - scriptChips: + header: 'runnableId' in upstream - ? 1 - : 'scripts' in upstream - ? (upstream.scripts?.length ?? 0) - : 0 + ? { label: upstream.summary || upstream.path, icons: 1 } + : 'scripts' in upstream && upstream.scripts?.length + ? upstream.scripts.length === 1 + ? { + label: upstream.scripts[0].summary || upstream.scripts[0].path, + icons: 1 + } + : { label: `${upstream.scripts.length} scripts`, icons: 2 } + : undefined }) : undefined return { @@ -1583,7 +1592,11 @@ ) }) let layoutPositions = $derived( - layoutAssetGraph(layoutInput, ADD_NODE_ID, assetsOnly ? PIPELINE_NODE_EXTRA_ROW : 0) + layoutAssetGraph( + layoutInput, + ADD_NODE_ID, + assetsOnly ? PIPELINE_NODE_EXTRA_ROW + PIPELINE_NODE_HEADER : 0 + ) ) /** Assets-only asset cards size to their text; every other node is `NODE.width`. */ diff --git a/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte b/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte index e7d80da8c1..9f2f486889 100644 --- a/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte +++ b/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte @@ -19,6 +19,7 @@ ShieldCheck, ShieldAlert, CheckCircle2, + ChevronDown, CircleSlash, Trash2, XCircle @@ -244,8 +245,7 @@ const n = upstream && 'scripts' in upstream ? upstream.scripts.length : 1 return `${n} script${n === 1 ? '' : 's'}` }) - const CHIP_CLASS = - 'shrink-0 h-5 min-w-5 rounded-md border bg-surface text-secondary hover:bg-surface-hover border-gray-300 dark:border-gray-600' + const HEADER_SELECTED = 'bg-surface-accent-selected hover:bg-surface-accent-selected text-accent' const CHIP_SELECTED = 'bg-surface-accent-selected border-border-selected hover:bg-surface-accent-selected text-accent' let producer = $derived(upstream && 'path' in upstream ? upstream : undefined) @@ -322,37 +322,72 @@ ) -{#snippet scriptChip(sc: { - path: string - summary?: string - language?: ScriptLang - unsaved?: boolean - selected?: boolean - onOpen: () => void -})} - +{#snippet scriptHeader()} + + {@const one = producer ?? (coProducers.length === 1 ? coProducers[0] : undefined)} + {@const headerClass = twMerge( + 'flex items-center gap-1.5 w-full min-w-0 px-2 text-3xs font-normal leading-none text-secondary hover:bg-surface-hover hover:text-primary' + )} + {#if one} + {@const isSelected = producer ? !!producer.selected : coSelected} + + {:else if coProducers.length > 1} + +
e.stopPropagation()} + onkeydown={(e) => e.stopPropagation()} + > + + {#snippet buttonReplacement()} + + {#each coProducers.slice(0, 2) as sc (sc.path)} + {#if sc.language} + + {:else} + + {/if} + {/each} + {coProducers.length} scripts + + + {/snippet} + +
+ {/if} {/snippet} {#snippet upstreamRow()} @@ -436,6 +471,7 @@ {selected} tone={data.error ? 'error' : undefined} subtitle={upstream ? upstreamRow : undefined} + header={producer || coProducers.length > 0 ? scriptHeader : undefined} width={data.width} surface={upstream ? 'primary' : 'secondary'} > @@ -554,50 +590,6 @@ {/if} - {#if producer} - {#if producer.runState} - - {/if} - {@render scriptChip(producer)} - {:else if coProducers.length === 1} - {@render scriptChip({ ...coProducers[0], selected: coSelected })} - {:else if coProducers.length > 1} - - -
e.stopPropagation()} onkeydown={(e) => e.stopPropagation()}> - - {#snippet buttonReplacement()} - - {#each coProducers.slice(0, 2) as s (s.path)} - {#if s.language} - - {:else} - - {/if} - {/each} - {#if coProducers.length > 2} - +{coProducers.length - 2} - {/if} - - {/snippet} - -
- {/if} {/snippet} diff --git a/frontend/src/lib/components/assets/AssetGraph/PipelineNodeCard.svelte b/frontend/src/lib/components/assets/AssetGraph/PipelineNodeCard.svelte index f4dc36fb72..82765e53b1 100644 --- a/frontend/src/lib/components/assets/AssetGraph/PipelineNodeCard.svelte +++ b/frontend/src/lib/components/assets/AssetGraph/PipelineNodeCard.svelte @@ -6,7 +6,11 @@ and the controls hung around the card. -->