This commit is contained in:
@@ -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>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user