Skip to content

Commit af07b16

Browse files
fix(table): show Stop button on optimistic-pending row cells
isExecInFlight required a jobId for `pending` status, gating it as "real backend pending" vs "optimistic flag only." The row-gutter Stop button keyed on this — so a freshly clicked Play sat as `pending` (no jobId) and the user couldn't cancel it until the server-side `queued` stamp arrived via SSE. With the dispatcher pre-batch stamping cells as `queued` (not `pending`) and no per-cell jobIds under batchTriggerAndWait, the gap was worse. Drop the jobId requirement. `pending` now counts as in-flight everywhere. Cancel writes `cancelled` to the cell exec authoritatively whether or not a real trigger.dev run exists yet — cancelling an optimistic cell means "don't run this," which is correct. Also collapse isOptimisticInFlight into isExecInFlight since the two helpers are now identical.
1 parent e76469a commit af07b16

2 files changed

Lines changed: 15 additions & 19 deletions

File tree

apps/sim/hooks/queries/tables.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ import type {
6969
WorkflowGroupDependencies,
7070
WorkflowGroupOutput,
7171
} from '@/lib/table'
72-
import { areOutputsFilled, optimisticallyScheduleNewlyEligibleGroups } from '@/lib/table/deps'
72+
import {
73+
areOutputsFilled,
74+
isExecInFlight,
75+
optimisticallyScheduleNewlyEligibleGroups,
76+
} from '@/lib/table/deps'
7377

7478
const logger = createLogger('TableQueries')
7579

@@ -869,7 +873,7 @@ export function useCancelTableRuns({ workspaceId, tableId }: RowMutationContext)
869873
const nextExecutions: RowExecutions = { ...executions }
870874
for (const gid in executions) {
871875
const exec = executions[gid]
872-
if (!isOptimisticInFlight(exec)) continue
876+
if (!isExecInFlight(exec)) continue
873877
// Preserve blockErrors so cells that already errored keep their
874878
// Error rendering after the stop — only cells without a value or
875879
// error should flip to "Cancelled".
@@ -1251,14 +1255,6 @@ function buildPendingExec(
12511255
}
12521256
}
12531257

1254-
/** Broader sibling of `isExecInFlight` from `lib/table/deps`: treats any
1255-
* `pending` (with or without a jobId) as in-flight. The optimistic-patch
1256-
* context uses this to avoid re-marking a cell we just flipped optimistically.
1257-
* The eligibility predicate uses the stricter version. */
1258-
function isOptimisticInFlight(exec: RowExecutionMetadata | undefined): boolean {
1259-
return exec?.status === 'running' || exec?.status === 'queued' || exec?.status === 'pending'
1260-
}
1261-
12621258
/**
12631259
* The single canonical run mutation. Every UI gesture (single cell, per-row
12641260
* Play, action-bar Play/Refresh, column-header menu) maps to a `groupIds` +
@@ -1295,7 +1291,7 @@ export function useRunColumn({ workspaceId, tableId }: RowMutationContext) {
12951291
const nextData = { ...r.data }
12961292
for (const groupId of targetGroupIds) {
12971293
const exec = executions[groupId] as RowExecutionMetadata | undefined
1298-
if (isOptimisticInFlight(exec)) continue
1294+
if (isExecInFlight(exec)) continue
12991295
// Mirror server eligibility for `mode: 'incomplete'`: skip cells whose
13001296
// outputs are filled, regardless of exec status. A cancelled/error
13011297
// cell with a leftover value from a prior run was rendering as filled

apps/sim/lib/table/deps.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ import type { RowData, RowExecutionMetadata, RowExecutions, TableRow, WorkflowGr
1010
const logger = createLogger('OptimisticCascade')
1111

1212
/**
13-
* True when the cell has a worker actively reserved — `queued` / `running`,
14-
* or `pending` after the scheduler stamped a jobId. Single source of truth
15-
* for the "is this exec in flight" classification across the eligibility
16-
* predicate, optimistic patches, status counters, and renderer. `pending`
17-
* without a jobId is the optimistic-flag-only state, not in-flight.
13+
* True when the cell is `pending` / `queued` / `running`. Single source of
14+
* truth for the "is this exec in flight" classification across the
15+
* eligibility predicate, optimistic patches, status counters, and renderer.
16+
* `pending` counts even without a jobId so the row-gutter Stop button is
17+
* available the moment the user clicks Play — the cancel path writes
18+
* `cancelled` authoritatively whether or not a real trigger.dev run exists
19+
* yet, which is correct: cancel means "don't run this."
1820
*/
1921
export function isExecInFlight(exec: RowExecutionMetadata | undefined): boolean {
2022
if (!exec) return false
2123
const s = exec.status
22-
if (s === 'queued' || s === 'running') return true
23-
if (s === 'pending' && exec.jobId) return true
24-
return false
24+
return s === 'queued' || s === 'running' || s === 'pending'
2525
}
2626

2727
/**

0 commit comments

Comments
 (0)