From c8c286516bdad5ff0491f459544943d74910310a Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Wed, 30 Sep 2026 19:47:11 +0200 Subject: [PATCH] fix: coloured run badge border; per-script delete when no combined delete; run button centred on the card Co-Authored-By: Claude Opus 5.5 (1M context) --- .../assets/AssetGraph/AssetGraphCanvas.svelte | 8 ++++++++ .../assets/AssetGraph/AssetNode.svelte | 17 +++++++++++++++-- .../assets/AssetGraph/RunStateChip.svelte | 8 ++++---- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte b/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte index 2bc8121180..6acd9a7e6c 100644 --- a/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte +++ b/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte @@ -1468,6 +1468,14 @@ } : onDeleteAssetUpstream && u ? { + // No combined delete, but each script it folds can still go on its + // own: in this view its node's menu is the only way to reach it. + scriptDeletes: (u.multiple ? u.runnableIds : [u.runnableId]) + .map((id) => runnables.get(id)?.data) + .filter((d) => d?.runnable_kind === 'script') + .map((d) => ({ path: d.path as string, unsaved: !!d.unsaved })), + deleteVerb: assetDeleteVerb, + onDeleteUpstream: (t: AssetUpstreamDelete) => onDeleteAssetUpstream?.(t), // The No-asset card stands for its scripts; an asset is built by them. deleteBlocked: data.noAsset ? !u.multiple diff --git a/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte b/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte index 30ea2e52c2..cd46b701d7 100644 --- a/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte +++ b/frontend/src/lib/components/assets/AssetGraph/AssetNode.svelte @@ -180,6 +180,9 @@ /** Assets-only view: the producing script and trigger no other asset * shares, which the menu offers to delete one by one or together. */ upstreamDelete?: import('./assetsOnlyView').AssetUpstreamDelete + /** When no combined delete is possible: the folded scripts, each deletable + * on its own. */ + scriptDeletes?: Array<{ path: string; unsaved: boolean }> onDeleteUpstream?: (target: import('./assetsOnlyView').AssetUpstreamDelete) => void deleteVerb?: 'Delete' | 'Archive' /** Why nothing can be deleted, when the producer is shared. */ @@ -233,7 +236,11 @@ let menuItems: Item[] = $derived( data.onDeleteUpstream && data.upstreamDelete ? deleteItems(data.upstreamDelete, data.onDeleteUpstream) - : data.deleteBlocked + : data.onDeleteUpstream && data.scriptDeletes?.length + ? data.scriptDeletes.map((script) => + deleteItems({ script }, data.onDeleteUpstream!) + ).flat() + : data.deleteBlocked ? [ { displayName: `Can't delete: ${data.deleteBlocked}`, @@ -686,7 +693,13 @@ cards. Drafts are runnable too via runScriptPreview, so no greyed-out state — the page-supplied callback handles the dispatch. --> -
+ +