fix: remove-from-View opens its dialog, error chip fits, no link to an undrawn asset

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Diego Imbert
2026-09-30 18:07:11 +02:00
co-authored by Claude Opus 5.5
parent 7422d4d7a1
commit 8d901de4bd
3 changed files with 31 additions and 14 deletions
@@ -1193,6 +1193,15 @@
onDeleteAssetUpstream && u && !u.multiple && r
? upstreamDeletion(u, r, v.upstream)
: undefined
// The scripts and triggers folded into this node, whose errors it reports.
const scriptIds = u ? (u.multiple ? u.runnableIds : [u.runnableId]) : []
const foldedIds = [
...scriptIds,
...m.edges
.filter((e) => e.kind === 'trigger-native' && scriptIds.includes(e.target))
.map((e) => e.source)
]
const foldedErrors = foldedIds.filter((id) => nodeFixes?.has(id)).length
const asset = { kind: data.asset_kind, path: data.path }
const scriptCount = u?.multiple ? u.runnableIds.length : 1
// Chips this estimate does not model keep the regular width.
@@ -1203,13 +1212,15 @@
title: data.noAsset
? `${scriptCount} script${scriptCount === 1 ? '' : 's'}`
: formatShortAssetPath(asset),
chip:
'none' in upstream
chip: foldedErrors
? `${foldedErrors} errors · Fix`
: 'none' in upstream
? 'External source'
: 'multiple' in upstream
? 'Multiple upstream nodes'
: `${upstream.trigger.label}${upstream.trigger.draft ? ' · draft' : ''}`,
runState: 'runState' in upstream && !!upstream.runState,
chipIcon: foldedErrors > 0,
scriptChips:
'runnableId' in upstream
? 1
@@ -1218,14 +1229,6 @@
: 0
})
: undefined
// The scripts and triggers folded into this node, whose errors it reports.
const scriptIds = u ? (u.multiple ? u.runnableIds : [u.runnableId]) : []
const foldedIds = [
...scriptIds,
...m.edges
.filter((e) => e.kind === 'trigger-native' && scriptIds.includes(e.target))
.map((e) => e.source)
]
return {
...data,
upstream,
@@ -27,6 +27,8 @@ export function assetsOnlyNodeWidth(n: {
kind: string
title: string
chip: string
/** The chip leads with an icon (the folded-errors Fix chip). */
chipIcon?: boolean
runState: boolean
/** Producing scripts: one chip for one, two icons and a "+N" for more. */
scriptChips: number
@@ -35,7 +37,7 @@ export function assetsOnlyNodeWidth(n: {
const text = Math.max(
textWidth(n.kind, 0.7),
textWidth(n.title, 0.75),
textWidth(n.chip, 0.65) + 12 + 2
textWidth(n.chip, 0.65) + 12 + 2 + (n.chipIcon ? 14 : 0)
)
// The run chip is sized for a two-digit count, so a new run never re-lays the graph.
const scripts =
@@ -1387,7 +1387,12 @@
fixes.set(`script:${path}`, {
explainer: [
'Runs after each write to ',
assetLink(asset),
// Not drawn when only this subscription names it: nothing to select.
shownGraph.edges.some(
(e) => e.asset_kind === asset.kind && e.asset_path === asset.path
)
? assetLink(asset)
: asset.path,
', but nothing writes it, so it never runs.'
],
actions: [
@@ -1465,8 +1470,15 @@
detail: unsaved
? 'Drops the draft.'
: 'Opens its archive or delete confirmation.',
run: () => {
if (mode !== 'edit') setMode('edit')
run: async () => {
if (mode !== 'edit') await setMode('edit')
// The pane takes the remove request only once it is open on the
// script: a request made as it mounts is its starting point.
if (!unsaved) {
pe.activeDraftPath = undefined
pe.selection = { kind: 'runnable', runnable_kind: 'script', path }
await tick()
}
handleRunnableMenuRemove({ runnable_kind: 'script', path, unsaved })
}
}