Skip to content

feat(workflows): wire Cancel button into workflow-editor test runs (TKAI-173) - #99

Open
yourbuddyconner wants to merge 1 commit into
mainfrom
conner/tkai-173-workflow-editor-cancel-button
Open

feat(workflows): wire Cancel button into workflow-editor test runs (TKAI-173)#99
yourbuddyconner wants to merge 1 commit into
mainfrom
conner/tkai-173-workflow-editor-cancel-button

Conversation

@yourbuddyconner

Copy link
Copy Markdown
Collaborator

Summary

Adds a Cancel button to the workflow-editor test-run UI so users can bail on a running test without refreshing the page. Wires client UI onto the existing backend cancellation path — no backend changes.

Two entry points:

  • Executions tab (WorkflowExecutionViewer): Cancel button appears in the execution summary pane next to Retry, whenever the selected execution's status is active per isActiveExecutionStatus.
  • Editor header, next to Test: Cancel test button appears while testRun.isPending OR the current execution is active, so users can bail before an execution row exists.

Both buttons use the armed-double-click pattern verbatim from packages/client/src/routes/automation/executions/$executionId.tsx:66-82 — first click arms, second confirms, 4s auto-disarm. State transitions and render gates are extracted as pure helpers in workflow-execution-viewer-model.ts so both call sites share the same model.

Backend is already implemented and unchanged:

  • Cancel API: POST /executions/:id/cancel in packages/worker/src/routes/executions.ts (and POST /:id/executions/:executionId/cancel in packages/worker/src/routes/workflows.ts)
  • Cleanup pipeline: runCancellationCleanup in packages/worker/src/workflows/cancel-cleanup.ts handles approvals, spawned sessions, in-flight tool calls, and CAS on the execution row.

Before: user had to refresh the page to know a stuck test run had drained; no way to actively stop it. After: Cancel button surfaces in the editor and in the execution viewer while the run is active; clicking twice sends the cancel request and the server-side cleanup pipeline drains the run.

Linear: https://linear.app/turnkey/issue/TKAI-173/

Test plan

  • pnpm -F @valet/client test — 281/281 pass (13 new tests covering the state machine + render gates)
  • pnpm -F @valet/client typecheck — clean
  • pnpm -F @valet/client build — clean (Vite build succeeded)
  • CI green

…KAI-173)

Add a Cancel button to the workflow-editor test-run surface so users can
bail out of an in-flight run without refreshing the page. The backend
cancellation path was already implemented (POST /executions/:id/cancel,
runCancellationCleanup for approvals + spawned sessions + in-flight
tool calls); this is client wiring only.

- Cancel button in the ExecutionSummaryPane on the Executions tab of
  the workflow editor, gated on the execution being non-terminal.
- Cancel button in the editor header next to Test, visible while the
  test-run mutation is pending or the selected execution is still
  active. Lets users bail during the brief window between clicking
  Test and the execution row appearing.
- Both use the two-phase armed-double-click pattern already established
  on the execution detail page (first click arms, second confirms,
  auto-disarms after 4s).
- Two new pure model helpers (getCancelButtonState,
  shouldShowExecutionCancel) drive both sites and are unit-tested.
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

Preview deployment: https://pr-99.dev-valet-turnkey-client.pages.dev

@yourbuddyconner
yourbuddyconner force-pushed the conner/tkai-173-workflow-editor-cancel-button branch from 68e9b2e to 0cfed1c Compare July 8, 2026 17:34

@xBalbinus xBalbinus left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracting getCancelButtonState / shouldShowExecutionCancel as tested pure functions is exactly the right shape. Two real bugs in the toolbar path and one state gap, then cleanup.

  1. Wrong-execution cancel ($workflowId.tsx:303): during the testRun.isPending window, handleCancelTestRun targets selectedExecutionId — which still holds the previously auto-selected execution (set on mount at :137) until onSuccess reassigns it (:277). A confirm-click in that window cancels the prior run (or errors against a terminal one) while toasting "Test run cancelled". The execution detail page is immune because its target is the immutable route param; this one isn't.

  2. That same isPending visibility branch appears unreachable (:423): test runs start only from the manual-run dialog, whose modal overlay covers the toolbar until onSuccess closes it — so the "bail during startup" window the comment describes can't actually be clicked. Given 1 + 2, the simplest fix is to drop the isPending branch and show the toolbar Cancel only once the new execution is selected.

  3. A stuck cancelling execution presents a live Cancel: button state derives only from client-side armed/isPending (workflow-execution-viewer.tsx:376), so once the mutation resolves, an execution the server holds in cancelling (local dev produces this routinely — instance.terminate() is unimplemented there) reverts to a re-clickable "Cancel" that will keep failing. getCancelButtonState already has the right shape to take the server status as an input and render a terminal "Cancelling…".

Cleanup, non-blocking: the toolbar and summary pane can render two independent Cancel buttons for the same execution with separate armed state (:600); the arm/4s-disarm machine is duplicated in both, and the toolbar copy misses the disarm-on-not-cancelable effect the pane has (:151) — a small useCancelArm hook would fix the drift and the stale-arm carryover; TERMINAL_EXECUTION_STATUSES is hand-copied from api/executions with only a keep-in-sync comment (workflow-execution-viewer-model.ts:9); and the persisted cancel reason hardcodes "test run" even when cancelling a non-test execution from the editor page (:313).

@xBalbinus xBalbinus left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Test-row Cancel button copies the two-phase armed-confirm pattern but omits the reset that its sibling ExecutionSummaryPane has ($workflowId.tsx:104 and :151). testCancelArmed is never cleared when the button hides or the run goes terminal, so the armed state carries from a finished run into a new one and a single click cancels the fresh run, defeating the confirm step. Mirror the sibling with useEffect(() => { if (!showTestCancel) setTestCancelArmed(false) }, [showTestCancel]).

shouldShowExecutionCancel and its private TERMINAL_EXECUTION_STATUSES copy (workflow-execution-viewer-model.ts:58) duplicate the exported isActiveExecutionStatus and TERMINAL_EXECUTION_STATUSES from @/api/executions.ts and will drift out of sync. Call the shared helper instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants