feat(tables): saved views with filter, sort, and column presets - #5961
feat(tables): saved views with filter, sort, and column presets#5961TheodoreSpeaks wants to merge 9 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview API & data: List/create/update/delete routes use existing table Table UI (gated by Grid: Honors Infrastructure: React Query hooks, API contracts, Reviewed by Cursor Bugbot for commit f085726. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryIntroduces feature-flagged saved table views.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the previously reported layout omission is addressed by capturing, auto-saving, and restoring view-owned layout fields, while concurrent layout and explicit saves now compose through atomic server-side patches.
|
| Filename | Overview |
|---|---|
| apps/sim/app/workspace/[workspaceId]/tables/[tableId]/table.tsx | Coordinates view selection, creation, saving, deletion, filter/sort state, hidden columns, and independent layout persistence. |
| apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx | Applies saved visibility and layout settings, re-seeds layout when views change, and routes layout writes to the active view. |
| apps/sim/lib/table/views/service.ts | Implements validated view persistence, including atomic server-side JSONB patch merging for independent concurrent updates. |
| apps/sim/app/api/table/[tableId]/views/[viewId]/route.ts | Adds authorized update and deletion endpoints for individual saved views. |
| apps/sim/app/api/table/[tableId]/views/route.ts | Adds authorized list and creation endpoints for table views. |
| packages/db/migrations/0270_table_views.sql | Adds the table-view persistence schema and associated constraints and indexes. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
UI[Table view controls] --> Hooks[Table view query mutations]
Hooks --> API[Table view API routes]
API --> Service[Table view service]
Service --> DB[(table_views)]
DB --> Service
Service --> UI
UI --> Grid[Table grid]
Grid -->|Layout patch| Hooks
Reviews (7): Last reviewed commit: "fix(tables): return 404 when patching a ..." | Re-trigger Greptile
|
@cursor review |
|
@cursor review |
|
@cursor review |
|
@cursor review |
|
@cursor review |
|
Addressing the two points in the latest Greptile summary — the 404 finding is fixed in 37f7db0, but I think both of these are already handled, so pushing back with the specifics rather than changing code: "View creation reads layout from asynchronously refreshed table metadata rather than the grid's current state"
It also can't diverge by construction: metadata is only the layout source when no view is active, and that is exactly the case where the grid is writing to metadata ( "top-level JSONB merging still allows overlapping updates to the same nested layout field to overwrite one another" True that Single-client sequential writes can't lose data either, because the grid always sends the complete map from local state ( |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 37f7db0. Configure here.
| onChange([...next]) | ||
| } | ||
|
|
||
| const hiddenCount = hiddenColumns.length |
There was a problem hiding this comment.
Stale hidden ids block column toggles
Medium Severity
ColumnsMenu builds its hide-all guard and active count from the raw hiddenColumns list, while the grid, dirty check, and save path already prune deleted column ids via effectiveHiddenColumns. After a previously hidden column is deleted, stale ids still count toward next.size, so the next.size >= columns.length guard can refuse further hides even though visible columns remain, and the Columns chip can stay lit with nothing actually hidden.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d04c96e. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f085726. Configure here.
| columns={columns} | ||
| workflowGroups={tableWorkflowGroups} | ||
| hiddenColumns={hiddenColumns} | ||
| onChange={setHiddenColumns} |
There was a problem hiding this comment.
Stale ids block column hiding
Medium Severity
ColumnsMenu still receives raw hiddenColumns even though deleted-column ids are already pruned into effectiveHiddenColumns for the grid, dirty check, and save. After a hidden column is removed, those leftover ids inflate next.size >= columns.length, so further hide toggles no-op and the Columns chip can stay lit with nothing actually hidden.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit f085726. Configure here.


Summary
Columnsmenu to show/hide columns, with workflow outputs nested under their group (hiding all of a group's children drops its spanning header)table_viewstable; "All" is the absence of a view, so no backfill and the table is always reachable unfilteredtable-viewsfeature flag (UI only — routes and migration ship ungated so a view saved during rollout survives the flag being turned off)Type of Change
Testing
Tested manually.
bun run type-check,bun run lint, all 11 CI audits, andcheck:migrations origin/stagingpass. 29 unit tests across the views service, API contracts, and feature flags.Checklist