Starting a fresh run means retyping values you already typed. The panel now
offers the other runs of this execution's own group - the group is keyed by
source flow, so a run of a different flow is never offered: matching its inputs
by name would be a coincidence, not a copy.
The copy fills the panel's pending edits rather than writing anything. That is
the whole trick: the values arrive with the unsaved-change styling already on
them, the user reviews them, and the single Save sends them in one bulk request.
No new write path, no new error handling.
It is deliberately partial, and says so. A file input holds a temp file on the
server, which the backend copies by reference when it reruns an execution; from
here there is only a path, and copying it would point this run at another run's
upload. Credentials are not copyable at all - the vault decrypts them
server-side. Both are reported in the summary rather than dropped quietly,
because a copy that silently leaves gaps is worse than one that names them.
Worth knowing before reaching for this: a rerun, bias rerun included, already
arrives fully populated - createBiasRerun calls copyReusableInputs, which carries
over every node input, the global descriptors, the authorizations and the
simulation descriptor. This is for the case that copies nothing: a new run
created from the flow.
An input already matching the source is not offered as a change, since it would
join the unsaved count and invite a pointless save.
555 frontend tests green; initial bundle unchanged at 2.88 kB over budget.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The globals go in a single request, so a failure belongs to the batch and not to
any field in it. Repeating the same text on every input said one thing N times
and implied N separate problems.
One message now sits above the fields, and it can say what the per-field version
could not: the request was all-or-nothing, so none of the values were saved. It
clears on the next edit, so a stale notice cannot outlive the state it described.
Node inputs keep their per-input errors: each is its own request, so a failure
there is attributable and partial success is real. File uploads likewise.
489 frontend tests green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The import action moves onto the name line: it was a flex container in a
baseline-aligned row, so it floated above the name and the type chip. It also
loses the data_array glyph for a plain upload arrow, since the dialog it opens
explains itself.
A list input now folds, on the same rule the two groups follow: unfolded while
it still needs attention, folded once it is satisfied. Five long answers filled
the whole aside otherwise. Folded, the row says how many items it is hiding, so
nothing disappears silently.
Long values were being typed through a slit ~320px wide. Every text value now
offers a larger box - on the head for a single value, per row for one item of a
list. Both write back through the ordinary pending change, so the panel's single
Save still decides when anything is sent, and the box is read-only when the
panel is.
Both dialogs now resolve the input by key when applying: editableInputs is
rebuilt on every poll, so the object captured when the dialog opened could be a
stale value to rebase an edit onto.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Filling a TEXT[] input meant clicking Add item and typing into one box after
another - painful when the items are five long interview questions that already
exist as an array somewhere. A multi-value input now carries an import icon next
to its type chip, opening a dialog to paste a JSON array whose elements become
the items.
The parser is deliberately strict and specific about what it refuses, because the
whole point is to save typing: a silent misread would be worse than typing the
items by hand. It names the offending element rather than coercing it - an object
would otherwise have arrived as "[object Object]" - and refuses an empty array
instead of quietly wiping the items. Numbers and booleans are converted, since
those are unambiguous as text.
The imported items are emitted as an ordinary pending change, so the panel's
single Save still governs when they are sent, and an import can be reviewed or
abandoned like any other edit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Global and node inputs are now collapsible sections, each headed by a badge: red
with the number still to fill in, green with a tick once none are. The count is
what makes collapsing safe - a folded group can never quietly be the thing
holding the run back.
A group starts open exactly when something in it is missing, and collapsed when
it is complete, so what needs attention is what you see without expanding
anything first. That is only the default: once the user toggles a group their
choice sticks, in both directions, rather than being overridden the next time the
counts change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The tally said "0 of 3" while ignoring the manual inputs below it, which are just
as required: the backend only reaches READY when every step is ready, so a step
missing its manual input blocks the start exactly as an unsatisfied global does.
It now counts the whole panel.
"Provided" is decided per input and passed down, rather than inferred in the
panel from a globals-only list. A global uses the backend's own
missingGlobalInputKeys; a node input is judged on its stored value, ignoring
unsaved edits - otherwise typing would make an input look satisfied before it was
sent. An empty list, or a list of blanks, does not count as supplied.
"Flow inputs" and "Manual inputs" are now "Global inputs" and "Node inputs",
which is what they are called everywhere else in the codebase and in the API.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each input opened with a centred gradient badge whose largest text read "Flow" -
the same word on every global input, so the most visual weight carried the least
information - followed by a "Type:" line and a four-row textarea. A one-word
positionTitle got the same box as a CV, and three short answers filled the panel.
An input is now one line of chrome - name, a small type chip, and a dot saying
whether it is still required - over a field that starts small. Removing an item
from a list is an icon rather than a full-width "Remove" button, which at this
width used to push the field out of the panel.
Saving is one action for the panel. Per-input buttons meant a click and a round
trip each, with nothing to say how much was still unsaved; a sticky bar now
reports the pending count and saves them together. Each one still goes through
the same single-input request, so a failure is still reported against its own
input.
The panel also stops ignoring missingGlobalInputKeys, which the backend has been
sending all along: it now shows "2 of 5 provided" and marks exactly the inputs
that block the start.
The editor is one template instead of four near-identical copies - global and
node, each single and multiple. That was not the goal here, but writing the same
change four times is how those four drifted apart in the first place. First tests
for this component.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>