Skip to content

fix(tables): scope optimistic stop-cancel to the active filtered view#4996

Open
TheodoreSpeaks wants to merge 1 commit into
stagingfrom
fix/stop-cancel-cache-scope
Open

fix(tables): scope optimistic stop-cancel to the active filtered view#4996
TheodoreSpeaks wants to merge 1 commit into
stagingfrom
fix/stop-cancel-cache-scope

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Follow-up to #4915 (raced the merge by minutes — Bugbot finding on the final review pass).

A filtered select-all Stop only cancels matching rows server-side, but the optimistic update flipped in-flight cells across every cached rows query — stale unfiltered views showed workflows as cancelled until the next refetch.

  • snapshotAndMutateRows gains an onlyKey option (exact-key scoping)
  • the cancel mutation passes the active view's exact cache key (filter + sort) when a filter is present; onSettled's invalidation reconciles other views as before

Test plan

  • bunx vitest run hooks/queries lib/table app/api/table (380 tests)
  • tsc, lint, strict api-validation all green

🤖 Generated with Claude Code

A filtered select-all Stop only cancels matching rows server-side, but
the optimistic update flipped in-flight cells across every cached rows
query — stale unfiltered views showed workflows as cancelled until the
refetch. snapshotAndMutateRows gains an onlyKey option; the cancel
mutation passes the active view's exact cache key (filter + sort) when a
filter is present, and onSettled's invalidation reconciles other views.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 12, 2026 7:09am

Request Review

@cursor

cursor Bot commented Jun 12, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Client-side React Query optimistic update only; API body unchanged and invalidation still reconciles other caches.

Overview
Fixes a filtered select-all Stop bug where the optimistic cancel updated every cached rows query, so rows outside the active filter briefly looked cancelled until refetch—even though the server only stopped matching rows.

onStopAllRows now passes the active view’s sort into cancelRunsMutate so the mutation can target the right React Query cache entry (filter + sort), matching the pattern used for async filter-scoped deletes.

useCancelTableRuns accepts optional sort on cancel params (client-only). When a filter is set, optimistic cell flips run only against that view’s infiniteRows key via new onlyKey on snapshotAndMutateRows; unfiltered / table-wide stops still walk all caches under rowsRoot. onSettled row invalidation is unchanged and reconciles other views.

Reviewed by Cursor Bugbot for commit afc9fbc. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a stale-state bug where an optimistic "Stop All" with an active filter was flipping cancelled status across all cached row views (including unfiltered ones), not just the view whose rows the server was actually cancelling.

  • snapshotAndMutateRows gains an onlyKey option that restricts the cache walk and cancelQueries to a single exact query key; without onlyKey the existing broad rowsRoot prefix-match is preserved.
  • useCancelTableRuns.onMutate now builds the exact infinite-rows cache key (filter + sort + TABLE_LIMITS.MAX_QUERY_LIMIT) when a filter is present and passes it as onlyKey; onSettled still invalidates all row queries for consistency.
  • onStopAllRows in table.tsx now forwards queryOptions.sort so the constructed key matches the actual cached query.

Confidence Score: 5/5

Safe to merge — the change is a targeted, well-scoped fix that reduces collateral cache mutation without altering the server-side behaviour or the onSettled reconciliation path.

The fix is self-contained: onlyKey narrows an optimistic update that was previously too broad, and the fallback to rowsRoot prefix-match preserves all existing non-filtered code paths. The key construction uses the same TABLE_LIMITS.MAX_QUERY_LIMIT and tableRowsParamsKey serialisation that the cache was originally populated with (confirmed in use-table.ts), so the exact-match lookup is reliable. onSettled still invalidates all row views, keeping consistency as a safety net.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/hooks/queries/tables.ts Adds onlyKey option to snapshotAndMutateRows and uses it in useCancelTableRuns.onMutate to restrict the optimistic update to the active filtered view's exact cache entry; onSettled continues to invalidate all row views.
apps/sim/app/workspace/[workspaceId]/tables/[tableId]/table.tsx Forwards queryOptions.sort into cancelRunsMutate so the cache key construction in onMutate matches the active query; adds sort to the useCallback dep array accordingly.

Sequence Diagram

sequenceDiagram
    participant UI as table.tsx / table-grid.tsx
    participant Hook as useCancelTableRuns
    participant QC as React Query Cache
    participant Server as API /cancel-runs

    UI->>Hook: onStopAllRows(filter, sort, excludeRowIds)
    Note over Hook: filter present → build onlyKey
    Hook->>QC: "cancelQueries({ queryKey: onlyKey, exact: true })"
    Note over QC: Only cancels in-flight fetch for active filtered view
    Hook->>QC: "getQueriesData({ queryKey: onlyKey, exact: true })"
    Note over QC: Snapshot only the active view
    Hook->>QC: setQueryData(onlyKey, optimisticCancel)
    Note over QC: Other cached views unchanged
    Hook->>Server: "POST /cancel-runs { scope: all, filter, excludeRowIds }"
    Server-->>Hook: 200 OK
    Hook->>QC: invalidateQueries(rowsRoot) — reconciles all views
Loading

Reviews (1): Last reviewed commit: "fix(tables): scope optimistic stop-cance..." | Re-trigger Greptile

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.

1 participant