feat: title pipeline schedule nodes with the schedule's summary

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Diego Imbert
2026-09-30 12:47:36 +02:00
co-authored by Claude Opus 5.5
parent 0050f462b3
commit 4cdbd11977
5 changed files with 26 additions and 17 deletions
@@ -718,6 +718,7 @@
missing: boolean
draft: boolean
schedule?: string
summary?: string
// First target script (drives the per-script create/edit flows).
runnable_path?: string
// Every target script: a single (kind, ref) — e.g. one schedule —
@@ -735,7 +736,8 @@
missing: boolean,
draft: boolean,
runnable_path?: string,
schedule?: string
schedule?: string,
summary?: string
) {
const prev = triggerSourceNodes.get(id)
if (!prev) {
@@ -746,6 +748,7 @@
missing,
draft,
schedule,
summary,
runnable_path,
runnable_paths: runnable_path ? [runnable_path] : []
})
@@ -802,7 +805,8 @@
// disabled `canEdit` (and the resulting click affordance)
// on every attached native trigger.
t.runnable_path,
t.schedule
t.schedule,
t.summary
)
edges.push({
id: `trig-${t.trigger_kind}:${sourceId}->${runnableId}`,
@@ -832,6 +836,7 @@
missing: info.missing,
draft: info.draft,
schedule: info.schedule,
summary: info.summary,
runnable_path: info.runnable_path,
// data_upload nodes go green once a file is staged for their
// target script (see readyDataUploadPaths / page dataUploadArgs).
@@ -75,6 +75,8 @@
draft?: boolean
// The cron, for a schedule: the node names its cadence instead of "Schedule".
schedule?: string
// Shown as the title over the trigger's path, when the trigger has one.
summary?: string
runnable_path?: string
// Page-supplied dispatcher that opens the matching native
// trigger drawer with `script_path` pre-filled. When absent
@@ -235,7 +237,7 @@
if (canEdit)
return {
kindLabel: `${kindName}${data.draft ? ' · draft' : unsaved ? ' · unsaved' : ''}`,
title: data.ref,
title: data.summary || data.ref,
tooltip: data.draft
? `Draft ${style.label}: ${data.ref} — created when you save the pipeline. Click to edit.`
: `Edit ${style.label} trigger: ${data.ref}`,
@@ -263,7 +265,7 @@
}
return {
kindLabel: `${displayMissing ? style.label : kindName}${displayMissing ? ' · missing' : unsaved ? ' · unsaved' : ''}`,
title: displayMissing ? 'no trigger row' : data.ref,
title: displayMissing ? 'no trigger row' : data.summary || data.ref,
tooltip:
missingTitle ??
(unsaved ? `Unsaved ${style.label}: ${data.ref}` : `${style.label}: ${data.ref}`),
@@ -309,7 +309,8 @@ function withTriggerDrafts(
runnable_path: d.config.script_path,
unsaved: true,
draft: true,
...(d.kind === 'schedule' ? { schedule: d.config.schedule as string } : {})
...(d.kind === 'schedule' ? { schedule: d.config.schedule as string } : {}),
...(d.config.summary ? { summary: d.config.summary as string } : {})
}))
]
}
@@ -214,8 +214,9 @@ export type AssetGraphTrigger =
// A pipeline-local `PipelineTriggerDraft`: `path` is the trigger it
// will be deployed as, and no row exists yet.
draft?: boolean
// A schedule's cron, filled in client-side, for the node's label.
// A schedule's cron and summary, filled in client-side, for the node's labels.
schedule?: string
summary?: string
}
// Macro-library → consumer edge: the consumer calls `macro_names` of
@@ -1381,13 +1381,13 @@
if (refs.length > 0) explicitOnByPath.set(r.path, refs)
}
const errors = pipelineNodeErrors(g, explicitOnByPath)
const crons = scheduleCrons.current
const schedules = scheduleInfo.current
return {
...g,
triggers: crons?.size
triggers: schedules?.size
? g.triggers.map((t) =>
t.trigger_kind === 'schedule' && t.path && !t.schedule && crons.has(t.path)
? { ...t, schedule: crons.get(t.path) }
t.trigger_kind === 'schedule' && t.path && !t.draft && schedules.has(t.path)
? { ...t, ...schedules.get(t.path) }
: t
)
: g.triggers,
@@ -2467,13 +2467,13 @@
}
)
// Crons of the deployed schedules on the graph, for their nodes' labels.
// Re-read with every graph load, so an edit in the schedule drawer shows.
let scheduleCrons = resource(
// Cron and summary of the deployed schedules on the graph, for their nodes'
// labels. Re-read with every graph load, so an edit in the schedule drawer shows.
let scheduleInfo = resource(
[() => $workspaceStore, () => graphRes.current],
async ([ws, g]) => {
const crons = new Map<string, string>()
if (!ws || !g) return crons
const info = new Map<string, { schedule: string; summary?: string }>()
if (!ws || !g) return info
const paths = new Set<string>()
for (const t of g.triggers) {
if (t.trigger_kind === 'schedule' && t.path && !t.missing) paths.add(t.path)
@@ -2482,13 +2482,13 @@
[...paths].map(async (path) => {
try {
const s = await ScheduleService.getSchedule({ workspace: ws, path })
crons.set(path, s.schedule)
info.set(path, { schedule: s.schedule, summary: s.summary || undefined })
} catch {
// Unreadable schedule: its node keeps the plain "Schedule" label.
}
})
)
return crons
return info
}
)