fix: Fixed draft workflow status
Server Deploy / deploy (push) Successful in 41s

This commit is contained in:
2026-07-21 12:09:19 +01:00
parent d9a33b0672
commit ec201a23a2
+23 -89
View File
@@ -16,23 +16,11 @@ type DragPayload = { kind: "lib"; stepId: string } | { kind: "move"; from: numbe
function ShellBadge({ interpreter }: { interpreter: "bash" | "powershell" }) {
const isBash = interpreter === "bash";
return (
<span
className={`rounded px-1.5 py-0.5 font-mono text-[10px] uppercase ${
isBash ? "bg-bash/15 text-bash" : "bg-pwsh/15 text-pwsh"
}`}
>
{isBash ? "bash" : "pwsh"}
</span>
);
return <span className={`rounded px-1.5 py-0.5 font-mono text-[10px] uppercase ${isBash ? "bg-bash/15 text-bash" : "bg-pwsh/15 text-pwsh"}`}>{isBash ? "bash" : "pwsh"}</span>;
}
function AdhocBadge() {
return (
<span className="rounded px-1.5 py-0.5 font-mono text-[10px] uppercase bg-signal/15 text-signal">
ad-hoc
</span>
);
return <span className="rounded px-1.5 py-0.5 font-mono text-[10px] uppercase bg-signal/15 text-signal">ad-hoc</span>;
}
// Stable snapshot of only the fields the editor controls. Excludes volatile
@@ -298,14 +286,7 @@ export default function WorkflowBuilder() {
updateRef(selectedIdxInWf, { overrides: { ...selectedRef.overrides, secret_refs: next } });
};
const upstreamOutputsFor = (i: number) =>
Array.from(
new Set(
sortedSteps
.slice(0, i)
.flatMap((r) => r.inline?.declared_outputs ?? libById(r.step_id)?.declared_outputs ?? []),
),
);
const upstreamOutputsFor = (i: number) => Array.from(new Set(sortedSteps.slice(0, i).flatMap((r) => r.inline?.declared_outputs ?? libById(r.step_id)?.declared_outputs ?? [])));
const DropZone = ({ pos }: { pos: number }) => (
<div
@@ -326,46 +307,28 @@ export default function WorkflowBuilder() {
<div className="flex items-center gap-1.5 text-sm">
<span className="text-text-secondary">Workflows /</span>
<span className="font-medium text-text-primary">{wf.name}</span>
<span className="text-text-secondary">
· {saving ? "Saving…" : lastSaved ? `Saved ${timeAgo(lastSaved)}` : "draft"}
</span>
<span className="text-text-secondary">· {saving ? "Saving…" : lastSaved ? `Saved ${timeAgo(lastSaved)}` : ""}</span>
</div>
<div className="ml-auto flex items-center gap-2">
<span className="rounded-full border border-border bg-surface-2 px-3 py-1 text-xs text-text-secondary">
{wf.target_server_ids.length} servers
</span>
<Link
href={`/workflows/${id}/runs`}
className="rounded-lg border border-border bg-surface-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary"
>
<span className="rounded-full border border-border bg-surface-2 px-3 py-1 text-xs text-text-secondary">{wf.target_server_ids.length} servers</span>
<Link href={`/workflows/${id}/runs`} className="rounded-lg border border-border bg-surface-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary">
Runs
</Link>
<Button variant="secondary" size="sm" onClick={() => setEditWorkflowOpen(true)}>
Edit
</Button>
<Button
size="sm"
loading={running}
onClick={run}
className="bg-signal text-signal-ink border-transparent hover:bg-signal/90"
>
<Button size="sm" loading={running} onClick={run} className="bg-signal text-signal-ink border-transparent hover:bg-signal/90">
Run workflow
</Button>
</div>
</div>
{error && (
<div className="border-b border-danger/30 bg-danger/10 px-4 py-2 text-sm text-danger">{error}</div>
)}
{notice && (
<div className="border-b border-signal/30 bg-signal/10 px-4 py-2 text-sm text-signal">{notice}</div>
)}
{error && <div className="border-b border-danger/30 bg-danger/10 px-4 py-2 text-sm text-danger">{error}</div>}
{notice && <div className="border-b border-signal/30 bg-signal/10 px-4 py-2 text-sm text-signal">{notice}</div>}
<div className="grid h-[calc(100vh-53px)] grid-cols-[1fr_320px]">
{/* CENTER: canvas */}
<main
className="overflow-auto bg-background bg-[radial-gradient(circle_at_1px_1px,theme(colors.border)_1px,transparent_0)] bg-[length:22px_22px] p-8"
>
<main className="overflow-auto bg-background bg-[radial-gradient(circle_at_1px_1px,theme(colors.border)_1px,transparent_0)] bg-[length:22px_22px] p-8">
<div className="pointer-events-none sticky top-0 z-10 flex justify-center pt-4">
<button
onClick={() => setPickerOpen(true)}
@@ -391,10 +354,7 @@ export default function WorkflowBuilder() {
<div className="flex w-fit max-w-[300px] flex-wrap items-center justify-center gap-1 rounded-full border border-dashed border-signal/55 bg-surface px-3 py-1">
<span className="text-[10px] uppercase text-text-secondary">passes</span>
{outs.map((o) => (
<span
key={o}
className="rounded bg-signal px-2 py-0.5 font-mono text-[11px] text-signal-ink"
>
<span key={o} className="rounded bg-signal px-2 py-0.5 font-mono text-[11px] text-signal-ink">
{o}
</span>
))}
@@ -409,14 +369,10 @@ export default function WorkflowBuilder() {
e.dataTransfer.setData("text/plain", JSON.stringify({ kind: "move", from: i }));
}}
onClick={() => setSelected(i)}
className={`w-[340px] cursor-pointer rounded-[10px] border bg-surface p-3 ${
isSelected ? "border-signal ring-2 ring-signal/40" : "border-border"
}`}
className={`w-[340px] cursor-pointer rounded-[10px] border bg-surface p-3 ${isSelected ? "border-signal ring-2 ring-signal/40" : "border-border"}`}
>
<div className="mb-2 flex items-center gap-2">
<span className="grid h-5 w-5 place-items-center rounded border border-border font-mono text-[10px] text-text-secondary">
{i + 1}
</span>
<span className="grid h-5 w-5 place-items-center rounded border border-border font-mono text-[10px] text-text-secondary">{i + 1}</span>
<span className="text-sm font-medium text-text-primary">{ref.inline?.name ?? lib?.name ?? ref.step_id}</span>
{ref.inline && <ShellBadge interpreter={ref.inline.interpreter} />}
{lib && !ref.inline && <ShellBadge interpreter={lib.interpreter} />}
@@ -450,9 +406,7 @@ export default function WorkflowBuilder() {
) : (
<div className="space-y-4">
<div>
<div className="mb-1 text-[11px] font-bold uppercase tracking-wide text-text-secondary">
Step {selected + 1} · Inspector
</div>
<div className="mb-1 text-[11px] font-bold uppercase tracking-wide text-text-secondary">Step {selected + 1} · Inspector</div>
<div className="flex items-center gap-2">
{selectedRef.inline && <ShellBadge interpreter={selectedRef.inline.interpreter} />}
{selectedLib && !selectedRef.inline && <ShellBadge interpreter={selectedLib.interpreter} />}
@@ -465,11 +419,7 @@ export default function WorkflowBuilder() {
<div className="space-y-4 border-b border-border pb-4">
<div>
<label className="mb-1 block text-xs uppercase text-text-secondary">Name</label>
<input
className={inputClass}
value={selectedRef.inline.name}
onChange={(e) => updateInline(selectedIdxInWf, { name: e.target.value })}
/>
<input className={inputClass} value={selectedRef.inline.name} onChange={(e) => updateInline(selectedIdxInWf, { name: e.target.value })} />
</div>
<div>
<label className="mb-1 block text-xs uppercase text-text-secondary">Interpreter</label>
@@ -494,8 +444,8 @@ export default function WorkflowBuilder() {
onChange={(e) => updateInline(selectedIdxInWf, { script: e.target.value })}
/>
<p className="mt-1 text-xs text-text-secondary">
Write <code className="text-signal">KEY=value</code> to <code className="text-signal">$WORKFLOW_ENV</code> to
expose it to later steps. Outputs are derived automatically on save.
Write <code className="text-signal">KEY=value</code> to <code className="text-signal">$WORKFLOW_ENV</code> to expose it to later steps. Outputs are derived
automatically on save.
</p>
</div>
</div>
@@ -512,8 +462,7 @@ export default function WorkflowBuilder() {
}
/>
<p className="mt-1 text-xs text-text-secondary">
Write <code className="text-signal">KEY=value</code> to <code className="text-signal">$WORKFLOW_ENV</code> to expose
it to later steps.
Write <code className="text-signal">KEY=value</code> to <code className="text-signal">$WORKFLOW_ENV</code> to expose it to later steps.
</p>
</div>
)}
@@ -525,9 +474,7 @@ export default function WorkflowBuilder() {
{(selectedRef.inline?.declared_inputs ?? selectedLib?.declared_inputs ?? []).map((param) => (
<div key={param.name}>
<div className="mb-1 font-mono text-xs text-text-primary">{param.name}</div>
{param.description && (
<div className="mb-1 text-[11px] text-text-secondary">{param.description}</div>
)}
{param.description && <div className="mb-1 text-[11px] text-text-secondary">{param.description}</div>}
<input
className={inputClass}
placeholder={param.default}
@@ -547,9 +494,7 @@ export default function WorkflowBuilder() {
<div className="border-b border-border pb-4">
<label className="mb-2 block text-xs uppercase text-text-secondary">Inputs · from upstream</label>
<div className="flex flex-wrap gap-1">
{upstreamOutputsFor(selected).length === 0 && (
<p className="text-xs text-text-secondary">No upstream outputs.</p>
)}
{upstreamOutputsFor(selected).length === 0 && <p className="text-xs text-text-secondary">No upstream outputs.</p>}
{upstreamOutputsFor(selected).map((o) => (
<span key={o} className="flex items-center gap-1 rounded bg-surface-2 border border-border px-2 py-0.5 font-mono text-[11px] text-text-primary">
<span className="text-[9px] uppercase text-text-secondary">in</span>
@@ -562,9 +507,7 @@ export default function WorkflowBuilder() {
<div className="border-b border-border pb-4">
<label className="mb-2 block text-xs uppercase text-text-secondary">Outputs · to $WORKFLOW_ENV</label>
<div className="flex flex-wrap gap-1">
{(selectedRef.inline?.declared_outputs ?? selectedLib?.declared_outputs ?? []).length === 0 && (
<p className="text-xs text-text-secondary">No declared outputs.</p>
)}
{(selectedRef.inline?.declared_outputs ?? selectedLib?.declared_outputs ?? []).length === 0 && <p className="text-xs text-text-secondary">No declared outputs.</p>}
{(selectedRef.inline?.declared_outputs ?? selectedLib?.declared_outputs ?? []).map((o) => (
<span key={o} className="flex items-center gap-1 rounded bg-signal px-2 py-0.5 font-mono text-[11px] text-signal-ink">
<span className="text-[9px] uppercase">out</span>
@@ -582,19 +525,10 @@ export default function WorkflowBuilder() {
<div className="font-mono text-[11px] font-semibold text-text-secondary">{g.group}</div>
{(groupKeys[g.group] ?? []).map((key) => {
const ref = `${g.group}/${key}`;
const checked = (
selectedRef.inline
? (selectedRef.inline.secret_refs ?? [])
: (selectedRef.overrides?.secret_refs ?? [])
).includes(ref);
const checked = (selectedRef.inline ? (selectedRef.inline.secret_refs ?? []) : (selectedRef.overrides?.secret_refs ?? [])).includes(ref);
return (
<label key={ref} className="ml-2 flex cursor-pointer items-center gap-2 text-xs text-text-primary">
<input
type="checkbox"
className="accent-signal"
checked={checked}
onChange={() => toggleSecretRef(ref)}
/>
<input type="checkbox" className="accent-signal" checked={checked} onChange={() => toggleSecretRef(ref)} />
<span className="font-mono">{key}</span>
</label>
);