feat(frontend): dynamically disable file-dependent actions in the node picker#22
Open
LukasHirt wants to merge 3 commits into
Open
feat(frontend): dynamically disable file-dependent actions in the node picker#22LukasHirt wants to merge 3 commits into
LukasHirt wants to merge 3 commits into
Conversation
mzner
previously approved these changes
Jul 24, 2026
Executor.Run only populates vars["file.*"] (and the currentPath that file actions require) when a non-empty resourcePath reaches it. The scheduler always calls Run with an empty resourcePath, and the manual "Run now" panel only sends one if the user optionally types it in — only the File Event Trigger's SSE path reliably supplies a real file. Add a pure hasUpstreamFileSource() graph-walk (frontend/src/utils/flowValidation.ts) and surface a non-blocking warning in NodeDetailsPanel when a file action (tag/comment/move/copy/rename) has no such trigger upstream. Signed-off-by: Lukas Hirt <info@hirt.cz>
…e picker Move the file-source guardrail from an after-the-fact warning to pick-time restriction: NodePicker.vue now receives the picker's source node id plus the current nodes/edges, reuses the existing hasUpstreamFileSource() BFS to decide whether that source node's upstream trigger reliably provides a file, and disables/grays out file-dependent action entries (tag, comment, move, copy, rename) with an inline reason when it doesn't. WorkflowBuilder threads nodes/edges/pickerConnectFrom into the picker to make this work. Kept the NodeDetailsPanel warning as a secondary safety net: Vue Flow lets users rewire an existing action node's incoming edge by dragging directly between already-placed nodes, bypassing the picker entirely, and workflows created via the REST API never go through the picker at all. Signed-off-by: Lukas Hirt <info@hirt.cz>
CI's e2e suite caught a real regression: build-workflow.spec.ts (and run-workflow.spec.ts) build a Manual Trigger -> LLM -> Add Tag chain, and the picker was disabling "Add Tag" because hasUpstreamFileSource() treated Manual Trigger the same as Schedule Trigger — both "not guaranteed", so both got hard-blocked. That's too strict for Manual Trigger specifically: unlike Schedule Trigger (scheduler.go always calls Run with resourcePath=""), a Manual Trigger's "Run now" flow can supply a file via its free-text WebDAV-path field (ExecutionsPanel.vue / runRequest.ResourcePath) — Manual Trigger + file action is a legitimate, common workflow shape, not a structural impossibility. Split the check in two: hasUpstreamFileSource() keeps its original, stricter "only Event Trigger is *reliable*" semantics for the informational NodeDetailsPanel warning (still nudges on both Manual and Schedule). canUpstreamProvideFile() is new and looser — only Schedule Trigger fails it — and NodePicker.vue now uses that one to decide what to hard-disable, so Manual Trigger no longer blocks file-dependent actions in the picker. Signed-off-by: Lukas Hirt <info@hirt.cz>
LukasHirt
force-pushed
the
feat/flow-file-source-validation
branch
from
July 24, 2026 20:49
928fae3 to
87e125e
Compare
mzner
self-requested a review
July 24, 2026 20:50
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backend investigation
Read
backend/pkg/executor/executor.goend-to-end plus the callers ofExecutor.Run(backend/pkg/service/workflows.go,backend/pkg/scheduler/scheduler.go,backend/pkg/sse/manager.go):vars["file.name"]/vars["file.content"]are only populated whenresourcePath != ""at the top ofRun()(executor.go:66-76). IfGetContentfails orresourcePathis empty, those vars are simply never set — no error, no fallback.runAction'stag/comment/move/copy/renamebranches all require a non-emptycurrentPath(seeded fromresourcePath) and return a hard runtime error ("...action needs both a target file and...") when it's empty.notifyis the only action that doesn't touchcurrentPathat all.resourcePathis non-empty depends entirely on who callsRun, not on the graph itself:scheduler.go:147—s.executor.Run(ctx, authHeader, *wf, "schedule", "")— always an empty string. A Schedule Trigger can never provide a file. This is structurally impossible, not just unlikely.service/workflows.goRunhandler (manual "Run now") —resourcePathcomes from an optional free-text field inExecutionsPanel.vue("File to run against (WebDAV path)"). It can work — Manual Trigger + file action is a legitimate, common workflow shape — but nothing in the graph guarantees the user filled it in.sse/manager.go:306— passes the real path from the file event that fired. The File Event Trigger is the only trigger that reliably supplies a file on every run.Decision (evolved across this PR)
NodeDetailsPanel.vue.NodePicker.vue: disable file-dependent action entries when the picker's source node's upstream trigger doesn't reliably provide a file.build-workflow.spec.tsandrun-workflow.spec.tsboth build aManual Trigger -> LLM -> Add Tagchain, and the picker was disabling "Add Tag" because the disable-check treated Manual Trigger the same as Schedule Trigger. That's too strict — Manual Trigger is only conditionally file-less (depends on what the user types into "Run now"), whereas Schedule Trigger is structurally file-less (the scheduler always callsRunwith an emptyresourcePath, full stop). Fixed by splitting the check in two:hasUpstreamFileSource()keeps its original, stricter "only Event Trigger is reliable" semantics — still used for the informationalNodeDetailsPanelnudge (fires for both Manual and Schedule).canUpstreamProvideFile()is new and looser — only Schedule Trigger fails it — and is whatNodePicker.vuenow uses to decide what to hard-disable. Manual Trigger no longer blocks file-dependent actions in the picker.What changed
frontend/src/utils/flowValidation.ts(new): pure, tested graph-walk.hasUpstreamFileSource(nodeId, nodes, edges)— true only if the upstream trigger isevent(or none is reachable at all). Used byNodeDetailsPanel's warning.canUpstreamProvideFile(nodeId, nodes, edges)— true unless the upstream trigger isschedule(the only structurally-impossible case). Used byNodePicker's hard-disable.isFileDependentActionType(actionType)—tag/comment/move/copy/renameare file-dependent;notifyis not.frontend/src/components/NodePicker.vue: newsourceNodeId/nodes/edgesprops. Disables file-dependent entries (grayed out, inline reason + tooltip, click no-ops) only when the source's upstream trigger is a Schedule Trigger.frontend/src/components/NodeDetailsPanel.vue: shows a non-blocking warning banner for file-dependent actions whose upstream trigger isn't an Event Trigger (Manual or Schedule) — kept as a secondary safety net, since Vue Flow lets users rewire an action node's incoming edge by dragging directly between existing nodes (bypassing the picker), and workflows created via the REST API never go through the picker at all.frontend/src/views/WorkflowBuilder.vue: threadspickerConnectFrom/nodes/edgesintoNodePicker, andnodes/edgesintoNodeDetailsPanel.Left the node picker's categorization, the "+" button, node positioning, config-modal OK-button/auto-open, and output hints untouched — those are owned by other in-flight changes.
Test plan
TDD throughout, including for the CI-driven follow-up fix (tests updated/added first, confirmed failing against the pre-fix code, then implementation, then confirmed passing):
frontend/tests/unit/flowValidation.spec.ts(14 cases):hasUpstreamFileSourcecovers direct manual→move flags, direct event→move doesn't, manual→llm→move still flags, event→llm→move doesn't, schedule-trigger case, orphan-node case.canUpstreamProvideFilecovers the same shapes but asserts Manual Trigger is not flagged and only Schedule Trigger is.frontend/tests/unit/NodePicker.spec.ts(5 cases): Move File not disabled for a manual-trigger source; disabled (with reason text) for a schedule-trigger source; not disabled for an event-trigger source; clicking a disabled entry doesn't emitselect; non-file action (Send Notification) stays enabled regardless of source.frontend/tests/unit/NodeDetailsPanel.spec.ts(3 cases): warns for manual→move, doesn't warn for event→move, doesn't warn for notify.npm run test:unit— 5 test files, 26 tests, all passingnpm run check:types— cleannpm run lint— cleanCI (
gh pr checks 22) re-run after the fix — see checks on this PR