From 09c8f3b1f3eef2409e212cdb26c7bd2f830dae89 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Wed, 5 Aug 2026 12:25:25 +0200 Subject: [PATCH 1/8] feat: redesign flow step, loop and branch settings panels (#10026) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: responsive modal step panel for the flow editor in sessions On narrow layouts the flow editor's step-details pane opens as a modal (double-click a graph node) instead of a split pane, with a dock/float toggle. Scoped to sessions via allowModalPanel; the full-page editor is unchanged. - FlowEditor: modal/docked modes gated by mount width + allowModalPanel, small header (step-id Badge + subtle dock/close), standing double-click hint, and a per-step hint in the name tooltip - selectionManager: onSelectIntent hook so flow-level panels (settings, input, triggers…) open the modal on single click - PropPickerWrapper: collapse the prop picker until connect and animate it in via AnimatedPane (runs-page pattern), no blue connect ring in modal mode - StepInputGen: drop the TAB/Wand autocompletion button + spinner (feature still works via focus + Tab) - InputTransformForm: decouple the Help dropdown from the AI suggestion - FlowModuleHeader: move 'Save to workspace' into an ellipsis dropdown Co-Authored-By: Claude Opus 4.8 (1M context) * fix: loop editor rendering and nested splitpanes splitters in the sessions modal - Loop iterator/parallelism: keep the picker split pane (forceExpanded) so the editor fills its box and the picker shows; the collapse-until-connect mode stays for the step inputs - Remove the intrusive AI TAB/Wand autocompletion button from IteratorGen (generation still runs headless via focus + Tab) - Size the iterator connect plug and restyle the loop header/labels/toggles - Scope the global `.splitter-hidden` splitter-hiding rule to direct children so it no longer leaks into nested Splitpanes under the sessions preview Co-Authored-By: Claude Opus 4.8 (1M context) * feat: redesign flow step advanced settings as a single toggle-first column Co-Authored-By: Claude Opus 4.8 (1M context) * feat: taller step test pane by default and restyle advanced section titles Co-Authored-By: Claude Opus 4.8 (1M context) * feat: show flow run-settings params disabled when a setting is toggled off Co-Authored-By: Claude Opus 4.8 (1M context) * feat: single-column for-loop panel reusing the run-settings accordion Co-Authored-By: Claude Opus 4.8 (1M context) * feat: single-column while-loop panel reusing the run-settings accordion Co-Authored-By: Claude Opus 4.8 (1M context) * feat: single-column branch panels reusing the run-settings accordion Co-Authored-By: Claude Opus 4.8 (1M context) * fix: auto-open modal panel when creating an AI agent tool Co-Authored-By: Claude Opus 4.8 (1M context) * feat: redesign branch panels with card layout and shared predicate editor Co-Authored-By: Claude Opus 4.8 (1M context) * refactor: remove per-setting status badges from flow map nodes Co-Authored-By: Claude Opus 4.8 (1M context) * chore: sync package-lock after windmill-utils-internal bump Co-Authored-By: Claude Opus 4.8 (1M context) * style: polish prop-picker plug button and branch panel layouts * fix: persist skip-if-stopped toggles in early stop settings * fix: open the step panel modal on demand and cap its width * fix: restore graph step setting badges, strip panel header chips instead * feat: docked panel header with detach action and open-details step menu * feat: width-based panel mode on every surface with inline detach action * refactor: single source for flow step settings and their defaults * docs: pin flow editor vocabulary in CONTEXT.md * fix: open the trigger panel on double click or a specific trigger * fix: keep module pickers inside their pane and dismissable * fix: drop the misleading chevron on the MCP tool entry * fix: resolve flow approvals against the job's workspace, not the nav one * refactor: derive the approval workspace from the job, not from callers * fix: restore S3 snippets and gate params while their setting is off * fix: restore branch mock controls and address review findings * chore: drop stray debug log from the flow map item * feat: pinned output section for loop and branch panels * fix: open the panel for deliberate navigation from the flow header * perf: mount branch predicate editors on demand * fix: skip predicate picker previews the previous step's result * fix: flow-level graph nodes open their panel on a single click * fix: open the step panel for AI chat selections, not for undo * chore: drop dead console.log and duplicated modalPanel doc * fix: re-sync expression editors and scope error-handler settings * fix: match the failure module exactly and ignore unselectable nodes * fix: keep concurrency editable, honour module cache_ttl, tighten panel ids * fix: open panel from indirect selections, use presence for value-driven toggles * fix: don't open settings on error-handler delete, flush editors on unmount * fix: guard editor destroy flush, keep retry kind reachable * refactor: name the run settings panel after the domain vocabulary * fix: only write editor flushes to the step they belong to * fix: bind step panels by id so a delete can't retarget editor writes * fix: don't let the trigger picker's escape close the drawer beneath it * docs: condense two comments to the constraint they record * fix: arbitrate escape through the overlay stack instead of deferring to it * fix: key nested step blocks by identity so anchored bindings can't go stale * fix: untrack the overlay-stack push and drop the frozen branch binding * chore: state the escape rationale once, key branch lists, format * fix: let the topmost overlay own escape instead of the graph * fix: keep the dynamic-input help box out of static template fields * fix: restore the graph connect on the for-loop iterator * fix: end connect mode with the modal and keep it to docked panels * fix: never enter graph connect mode from the modal panel * fix: reveal inserted steps, restore editor pane size, unleak the drawer stack * fix: keep the enable-AI popover reachable in session panes * feat: add the connect policy and its single armed slot * refactor: one picker for every expression input * refactor: route every connect through one armed slot * fix: give every connect button the same footprint * fix: keep the connect ring from showing through the button * fix: keep flow card actions right-aligned beside the detach button * fix: give the connect ring an opaque ground to mask against * feat: dock the panel back without reopening it * feat: dock the panel from the graph control bar * style: round the graph control bar and size its glyphs * style: customize the graph controls through their supported api * style: build the graph control bar from lucide icons * fix: use the graph's tooltip component in the zoom controls * style: pad the graph controls and enlarge their glyphs * style: pad the graph controls and put dock at the bar's end * refactor: give settings rows the same popover picker as other expressions * fix: pass the wrapper's pickable properties to nested inputs * refactor: stack step settings and render every expression through the step input form * feat: split loop panels into tabs and rework the approval form * feat: anchor drawers to their host pane and give them a size floor * fix: mark the loop iterator expression as required * refactor: badge ee-only toggles instead of a warning line * fix: flag an empty loop iterator expression as an error * refactor: pick the early-stop flow status from one toggle group * fix: keep parallel loops uncapped unless a limit is opted into * fix: scope the overlay stack to its host and disarm connect on dismissal * fix: anchor the trigger picker to its host pane * feat: move diff into the menu when the top bar is narrow * fix: gate the result logs toggle to the graph popover * feat: raise the modal-panel breakpoint to 1280 * fix: anchor flow editor popovers and fullscreen to their host pane * fix: anchor overlays to their host pane and mute them when hidden * fix: portal hosted modals and menus into the pane they anchor to * fix: keep non-listening dialogs off the overlay stack * fix: drop the topmost gate from confirmation dialogs * fix: silence overlays in a collapsed preview panel * feat: rework the branch panels with tabs, reordering and add/delete * refactor: fold the detached-panel chrome into the card header * fix: give every flow panel a titled card header * fix: stop the step panel oscillating on an auto-height editor * feat: consolidate script panel actions and restore branch predicate AI * fix: restore the logs toggle on the flow result popover * fix: collapse the idle property picker in modal step panels * fix: stop the docked pane scrolling alongside its panel * fix: space the last settings row off the panel bottom * revert: always show the property picker pane in step panels * chore: keep the inline script AI button identical to main * fix: ask for AI input suggestions on click, not on hover * fix: keep graph connects armed and remount the parallelism input * style: reveal the predicate AI button on row hover * style: give branch cards a handle and delete column * refactor: arbitrate flow overlay escape through Disposable * fix: give the popover picker its results and re-narrow the EE badge * docs: correct loopSubset and guard the modal width measurement * fix: insert picked properties at the cursor in expression inputs * fix: give the expanded-subflow panel the shared header chrome * style: rename the suspend setting to Suspend until approval/resume * feat: open a step's modal when clicking the step already selected * feat: add an auto/attached/detached toggle for the step panel * refactor: pick the step panel's placement from one named menu * refactor: keep the panel-mode module's exports to what is consumed * feat: show each configured setting's value on its badge * fix: carry the suspend rename into the step settings registry * docs: name both gestures in the step explore hint * test: pin where the step panel goes for a given width and preference --------- Co-authored-by: Claude Opus 4.8 (1M context) --- AGENTS.md | 1 + CONTEXT.md | 38 ++ frontend/src/lib/components/ArgInput.svelte | 3 +- .../lib/components/EditableSchemaForm.svelte | 5 +- frontend/src/lib/components/Editor.svelte | 8 +- .../src/lib/components/FlowBuilder.svelte | 58 +- .../src/lib/components/FlowPlugConnect.svelte | 61 +- .../lib/components/FlowPreviewContent.svelte | 1 - .../FlowStatusWaitingForEvents.svelte | 13 +- .../src/lib/components/FlowWrapper.svelte | 1 + frontend/src/lib/components/IconedPath.svelte | 4 +- .../lib/components/InputTransformForm.svelte | 618 ++++++++++-------- .../components/SchemaFormWithArgPicker.svelte | 5 +- .../components/ScriptAdvancedSettings.svelte | 5 +- .../src/lib/components/SimpleEditor.svelte | 6 +- frontend/src/lib/components/Toggle.svelte | 202 +++--- .../lib/components/copilot/IteratorGen.svelte | 66 +- .../components/copilot/PredicateGen.svelte | 19 +- .../components/copilot/StepInputGen.svelte | 159 ++--- .../components/copilot/StepInputsGen.svelte | 51 +- .../copilot/chat/ContextTextarea.svelte | 2 +- .../copilot/chat/flow/FlowAIChat.svelte | 9 +- frontend/src/lib/components/custom_ui.ts | 2 + .../lib/components/flows/DebounceLimit.svelte | 40 +- .../lib/components/flows/FlowEditor.svelte | 288 +++++++- .../lib/components/flows/branchOps.test.ts | 55 ++ .../src/lib/components/flows/branchOps.ts | 82 +++ .../components/flows/common/FlowCard.svelte | 7 + .../flows/common/FlowCardHeader.svelte | 294 +++++---- .../flows/common/FlowPanelChrome.svelte | 29 + .../common/FlowPanelPlacementPicker.svelte | 70 ++ .../flows/content/AgentToolWrapper.svelte | 4 +- .../content/BranchPredicateEditor.svelte | 94 +-- .../flows/content/DynamicInputHelpBox.svelte | 9 +- .../flows/content/ExpandedSubflowStep.svelte | 12 +- .../flows/content/FlowBranchAllWrapper.svelte | 11 +- .../flows/content/FlowBranchOneWrapper.svelte | 23 +- .../content/FlowBranchesAllWrapper.svelte | 301 ++++++--- .../content/FlowBranchesOneWrapper.svelte | 297 +++++---- .../flows/content/FlowEditorPanel.svelte | 8 +- .../content/FlowEnvironmentVariables.svelte | 5 + .../components/flows/content/FlowLoop.svelte | 562 +++++++--------- .../flows/content/FlowModuleCache.svelte | 65 +- .../flows/content/FlowModuleComponent.svelte | 432 ++---------- .../flows/content/FlowModuleDebounce.svelte | 2 + .../content/FlowModuleDeleteAfterUse.svelte | 41 +- .../flows/content/FlowModuleEarlyStop.svelte | 596 ++++++++--------- .../flows/content/FlowModuleHeader.svelte | 175 +---- .../flows/content/FlowModuleMock.svelte | 81 +-- .../FlowModuleMockTransitionMessage.svelte | 145 ---- .../flows/content/FlowModuleSkip.svelte | 125 ++-- .../flows/content/FlowModuleSleep.svelte | 88 ++- .../flows/content/FlowModuleSuspend.svelte | 396 +++++------ .../flows/content/FlowModuleTimeout.svelte | 75 +-- .../flows/content/FlowModuleWrapper.svelte | 88 ++- .../flows/content/FlowResult.svelte | 7 - .../flows/content/FlowRetries.svelte | 537 ++++++++------- .../flows/content/FlowRunSettings.svelte | 371 +++++++++++ .../flows/content/FlowSettings.svelte | 14 +- .../flows/content/FlowWhileLoop.svelte | 213 +++--- .../flows/content/McpToolEditor.svelte | 226 +++---- .../flows/content/StepSettingsBadges.svelte | 30 + .../flows/content/SuspendDrawer.svelte | 17 +- .../flows/content/WebsearchToolDisplay.svelte | 17 +- .../flows/flowDeleteController.test.ts | 6 +- .../components/flows/flowDeleteController.ts | 4 +- .../components/flows/flowPanelMode.svelte.ts | 28 + .../components/flows/flowStepSettings.test.ts | 140 ++++ .../lib/components/flows/flowStepSettings.ts | 362 ++++++++++ .../flows/header/FlowPreviewButtons.svelte | 7 +- .../flows/map/FlowErrorHandlerItem.svelte | 17 +- .../flows/map/FlowModuleSchemaItem.svelte | 147 +---- .../map/FlowModuleSchemaItemViewer.svelte | 9 + .../flows/map/FlowModuleSchemaMap.svelte | 55 +- .../flows/map/InsertModuleInner.svelte | 12 +- .../lib/components/flows/map/MapItem.svelte | 27 +- .../components/flows/map/VirtualItem.svelte | 1 + .../lib/components/flows/moduleSlot.test.ts | 90 +++ .../src/lib/components/flows/moduleSlot.ts | 62 ++ .../components/flows/panelPlacement.test.ts | 25 + .../lib/components/flows/panelPlacement.ts | 29 + .../flows/pickers/TopLevelNode.svelte | 2 +- .../pickers/WorkspaceScriptPicker.svelte | 2 +- .../pickers/WorkspaceScriptPickerQuick.svelte | 13 +- .../flows/propPicker/ExpressionPicker.svelte | 105 +++ .../flows/propPicker/OutputPickerInner.svelte | 10 +- .../flows/propPicker/PropPickerWrapper.svelte | 181 ++--- .../flows/propPicker/connectPolicy.test.ts | 37 ++ .../flows/propPicker/connectPolicy.ts | 29 + .../flows/propPicker/useConnect.svelte.ts | 84 +++ frontend/src/lib/components/flows/types.ts | 19 + .../lib/components/graph/FlowGraphV2.svelte | 64 +- .../components/graph/GraphZoomControls.svelte | 35 + .../components/graph/GroupModuleIcons.svelte | 6 +- .../components/graph/graphBuilder.svelte.ts | 11 +- .../graph/renderers/edges/BaseEdge.svelte | 5 +- .../graph/renderers/nodes/AIToolNode.svelte | 4 +- .../renderers/nodes/CollapsedGroupNode.svelte | 5 +- .../graph/renderers/nodes/ModuleNode.svelte | 20 +- .../renderers/nodes/NewAIToolNode.svelte | 192 +++--- .../graph/renderers/nodes/TriggersNode.svelte | 6 +- .../renderers/triggers/TriggersWrapper.svelte | 76 ++- .../components/graph/selectionUtils.svelte.ts | 41 +- frontend/src/lib/components/prop_picker.ts | 3 + .../recording/FlowRecordingReplay.svelte | 1 - .../runs/FlowExecutionStatus.svelte | 11 +- .../lib/components/runs/JobRunsPreview.svelte | 1 - .../schema/EditableSchemaDrawer.svelte | 280 ++++---- .../components/triggers/TriggersEditor.svelte | 2 +- frontend/src/lib/transitions.ts | 44 ++ .../(root)/(logged)/run/[...run]/+page.svelte | 1 - 111 files changed, 5583 insertions(+), 3997 deletions(-) create mode 100644 CONTEXT.md create mode 100644 frontend/src/lib/components/flows/branchOps.test.ts create mode 100644 frontend/src/lib/components/flows/branchOps.ts create mode 100644 frontend/src/lib/components/flows/common/FlowPanelChrome.svelte create mode 100644 frontend/src/lib/components/flows/common/FlowPanelPlacementPicker.svelte delete mode 100644 frontend/src/lib/components/flows/content/FlowModuleMockTransitionMessage.svelte create mode 100644 frontend/src/lib/components/flows/content/FlowRunSettings.svelte create mode 100644 frontend/src/lib/components/flows/content/StepSettingsBadges.svelte create mode 100644 frontend/src/lib/components/flows/flowPanelMode.svelte.ts create mode 100644 frontend/src/lib/components/flows/flowStepSettings.test.ts create mode 100644 frontend/src/lib/components/flows/flowStepSettings.ts create mode 100644 frontend/src/lib/components/flows/moduleSlot.test.ts create mode 100644 frontend/src/lib/components/flows/moduleSlot.ts create mode 100644 frontend/src/lib/components/flows/panelPlacement.test.ts create mode 100644 frontend/src/lib/components/flows/panelPlacement.ts create mode 100644 frontend/src/lib/components/flows/propPicker/ExpressionPicker.svelte create mode 100644 frontend/src/lib/components/flows/propPicker/connectPolicy.test.ts create mode 100644 frontend/src/lib/components/flows/propPicker/connectPolicy.ts create mode 100644 frontend/src/lib/components/flows/propPicker/useConnect.svelte.ts create mode 100644 frontend/src/lib/components/graph/GraphZoomControls.svelte create mode 100644 frontend/src/lib/transitions.ts diff --git a/AGENTS.md b/AGENTS.md index bbf3952325..e39d4ebede 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,6 +23,7 @@ Open-source platform for internal tools, workflows, API integrations, background - **Code review**: review the current PR or branch against the shared review policy in `REVIEW.md` (severity triage, public-surface checklist, AGENTS.md compliance, test-coverage assessment). The skill at `.agents/skills/local-review/SKILL.md` orchestrates it. All three CLIs auto-discover the same SKILL — Claude reads `.claude/skills/` (symlinked to the canonical `.agents/skills/` file), Codex and Pi read `.agents/skills/` directly. Invoke with `/local-review` in Claude Code, `$local-review` (or `/skills` selector) in Codex, or `pi --skill local-review` / `/skill:local-review` in Pi. For a Codex-driven pass that mirrors the `codex-pr-review` GitHub action against your unpushed work (committed + uncommitted) before you push, use `/local-review-codex` (`.agents/skills/local-review-codex/`) — same `REVIEW.md` policy, `gpt-5.6-sol`, `xhigh` reasoning; requires the `codex` CLI >= 0.144.1. - **Domain guides**: `.claude/skills/native-trigger/` and `frontend/tutorial-system-guide.mdc` - **Brand/UI guidelines**: `frontend/brand-guidelines.md` +- **Domain vocabulary**: `CONTEXT.md` — the words this codebase uses for its own concepts (step, step setting, trigger step, …). Name things the way it does. - **CLI commands**: when adding/modifying/removing a command, subcommand, option, or description in `cli/src/commands/`, run `python system_prompts/generate.py` to refresh `system_prompts/auto-generated/` and `cli/src/guidance/skills.gen.ts`. The CLI docs the agents use to operate `wmill` are derived from the source — stale generated files give agents the wrong flags. - **Session recorder**: `frontend/src/lib/components/recording/` is also the recorder `wmill app dev --recording` serves, vendored into the CLI as `cli/src/commands/app/devRecorderBundle.gen.ts`. After changing `rawAppSnapshot.ts` or `rawAppRecording.svelte.ts`, run `bun run gen:dev-recorder` from `cli/` (`cli/test/dev_recorder_bundle_unit.test.ts` fails otherwise). diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 0000000000..6efb92b669 --- /dev/null +++ b/CONTEXT.md @@ -0,0 +1,38 @@ +# Windmill + +Open-source platform for internal tools, workflows, API integrations, background jobs and UIs. This file pins the vocabulary that is specific to Windmill's domain, so that code, docs and reviews name the same thing the same way. + +## Language + +### Flows + +**Step**: +One node of a flow — the unit a user selects in the graph and configures in the right-hand panel. Typed as `FlowModule` in code. +_Avoid_: module (ambiguous with the architectural sense), node, action + +**Step setting**: +A per-step runtime option stored on the step itself: retries, error handling, timeout, concurrency limit, priority, cache, debounce, early stop, skip, suspend, sleep, lifetime. Distinct from the step's inputs and its code. The panel that edits them is the **run settings** tab; a single setting is still a step setting. +_Avoid_: advanced setting, step config, flow option + +**Configured**: +Said of a step setting whose config object is present on the step. Deliberately not the same as "would change the runtime's behaviour" — a setting can be configured and still be a no-op (`sleep` of `0`). Every surface that answers "is this setting on?" answers it this way. +_Avoid_: enabled, active, effective + +**Trigger step**: +The first step of a polling flow. It runs on a schedule and returns the items found since its last run; an empty return means there is nothing to process and the flow stops early, marked skipped rather than failed. +_Avoid_: poll script, trigger node, schedule step + +**Default predicate**: +The `stop_after_if` expression seeded onto a trigger step at creation, encoding what "nothing new" looks like. One value, owned in one place, shared by every path that creates a trigger step. + +**Connect**: +Arming an input so that the next property picked fills it. A property can be picked from the prop picker or, when the panel is docked beside the graph, by clicking a step node's output. At most one input is armed per panel, so a pick always has exactly one destination. +_Avoid_: link, bind, plug (the icon is a plug; the action is connecting) + +**Step input**: +One argument of a step, edited in the step's input form. Its prop picker is a pane beside the form, always visible, so previous results can be browsed without connecting. +_Avoid_: argument field, param + +**Expression input**: +Any other place a property can be picked into: the loop iterator, skip and early-stop predicates, the retry condition, a branch predicate, timeout. Its prop picker opens in a popover from the connect button rather than taking a pane. +_Avoid_: JS field, code input diff --git a/frontend/src/lib/components/ArgInput.svelte b/frontend/src/lib/components/ArgInput.svelte index de5517add3..5ee7a5f429 100644 --- a/frontend/src/lib/components/ArgInput.svelte +++ b/frontend/src/lib/components/ArgInput.svelte @@ -719,7 +719,8 @@ onkeydown: () => (ignoreValueUndefined = true), placeholder: placeholder ?? defaultValue ?? '', min: extra['min'], - max: extra['max'] + max: extra['max'], + step: extra['step'] }} {error} bind:value diff --git a/frontend/src/lib/components/EditableSchemaForm.svelte b/frontend/src/lib/components/EditableSchemaForm.svelte index 5813926abd..5ceef0fbf0 100644 --- a/frontend/src/lib/components/EditableSchemaForm.svelte +++ b/frontend/src/lib/components/EditableSchemaForm.svelte @@ -932,7 +932,10 @@ {/if} diff --git a/frontend/src/lib/components/copilot/chat/ToolExecutionDisplay.svelte b/frontend/src/lib/components/copilot/chat/ToolExecutionDisplay.svelte index a1ee9984e5..754db1aac0 100644 --- a/frontend/src/lib/components/copilot/chat/ToolExecutionDisplay.svelte +++ b/frontend/src/lib/components/copilot/chat/ToolExecutionDisplay.svelte @@ -1,12 +1,11 @@