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) <noreply@anthropic.com>
This commit is contained in:
Diego Imbert
2026-09-30 19:47:11 +02:00
co-authored by Claude Opus 5.5
parent b61da57c35
commit c8c286516b
3 changed files with 27 additions and 6 deletions
@@ -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
@@ -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. -->
<div class="absolute -left-3 top-1/2 -translate-y-1/2 z-10">
<!-- Centred on the card, below the header tab when there is one. -->
<div
class={twMerge(
'absolute -left-3 top-1/2 -translate-y-1/2 z-10',
hasHeader && !data.bannerOnly && 'top-[calc(50%+11px)]'
)}
>
<button
type="button"
onclick={runProducers}
@@ -8,12 +8,12 @@
<div
class={twMerge(
'shrink-0 flex items-center gap-0.5 px-1 py-0.5 rounded-sm',
'shrink-0 flex items-center gap-0.5 px-1 py-0.5 rounded-sm border',
rs.status === 'running'
? 'bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-300'
? 'bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-300 border-blue-300 dark:border-blue-700'
: rs.status === 'success'
? 'bg-emerald-100 dark:bg-emerald-900/40 text-emerald-700 dark:text-emerald-300'
: 'bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-300',
? 'bg-emerald-100 dark:bg-emerald-900/40 text-emerald-700 dark:text-emerald-300 border-emerald-300 dark:border-emerald-700'
: 'bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-300 border-red-300 dark:border-red-700',
className
)}
title={`${