feat(realtime): live workspace tables list, sharing one invalidation-room impl - #6053
Conversation
…room impl Bring the tables list to parity with the files list: a create/rename/move/delete/ restore now propagates to every viewer live instead of waiting out the 30s staleTime. Following the files pattern, but factoring the two into one shared implementation rather than copy-pasting. - add ROOM_TYPES.WORKSPACE_TABLES + its authz resolver (workspace-id-addressed, reuses the workspace resolver like workspace-files) - extract setupWorkspaceInvalidationRoom (server) and useWorkspaceInvalidationRoom (client) — the presence-free, workspace-scoped live-list room; files and tables now both bind to it, so they can never drift. Event/room names derive from the room type. Replaces the standalone workspace-files handler + hook - notifyWorkspaceTablesChanged fanout fired from the table service (createTable, renameTable, moveTableToFolder, deleteTable, restoreTable) so it covers both the HTTP routes AND copilot, which call the service directly - relay /api/workspace-tables-changed endpoint; wire the hook into the tables page - consolidate the handler test into one suite run against both room types
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Server fan-out: Client: tables page uses Reviewed by Cursor Bugbot for commit 0f13492. Configure here. |
Greptile SummaryAdds live workspace tables-list invalidation by sharing one presence-free invalidation-room implementation with workspace files.
Confidence Score: 5/5This PR appears safe to merge; no blocking failures remain from prior or new eligible follow-up findings. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/realtime/src/handlers/workspace-invalidation-room.ts | Generalized workspace-files join/leave into a shared presence-free invalidation room parameterized by room type. |
| apps/sim/lib/table/service.ts | Fans out table-list invalidation after create/rename/move/delete/restore, with skipNotify for folder cascades. |
| apps/sim/lib/folders/lifecycle.ts | Notifies table live-list on folder CRUD/restore via notifyFolderResourceChanged. |
| apps/sim/app/workspace/[workspaceId]/hooks/use-workspace-invalidation-room.ts | Shared client join/retry/leave and onChanged invalidation for files and tables rooms. |
| apps/realtime/src/routes/http.ts | Adds workspace-tables-changed internal relay endpoint mirroring workspace-files-changed. |
Sequence Diagram
sequenceDiagram
participant UI as Tables UI
participant Hook as useWorkspaceTablesRoom
participant RT as Realtime socket
participant Svc as table/folder service
participant HTTP as /api/workspace-tables-changed
UI->>Hook: mount (workspaceId)
Hook->>RT: join-workspace-tables
Svc->>HTTP: notifyWorkspaceTablesChanged
HTTP->>RT: emit workspace-tables-changed
RT->>Hook: workspace-tables-changed
Hook->>UI: invalidate table + folder queries
Reviews (3): Last reviewed commit: "fix(realtime): skip per-table live-list ..." | Re-trigger Greptile
Fold in the follow-up: a table folder create/rename/move/delete/restore now propagates to the tables list live too, so the browser is fully consistent. - generic notifyFolderResourceChanged(resourceType, workspaceId) dispatches the workspace live-list signal by resource type (a map, not a special-case if), so file/knowledge_base/workflow are no-ops today and gain liveness by adding a map entry when they adopt an invalidation room - fired from the shared folder lifecycle (createFolder/updateFolder/deleteFolder/ restoreFolder), covering routes AND copilot - the tables room hook now invalidates the table folders query too, not just the tables list, since the page renders both
|
@cursor review |
A folder delete/restore already fires one folder-level notifyFolderResourceChanged for the whole subtree, but the cascade also calls deleteTable/restoreTable per table — each awaiting its own notifyWorkspaceTablesChanged. A folder with many tables would run N+1 sequential relay calls (each bounded by NOTIFY_TIMEOUT_MS), blocking the mutation. Add a skipNotify option the cascade passes so only the one folder-level notify fires.
|
@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 0f13492. Configure here.
Summary
Brings the tables list to parity with the files list: a create/rename/move/delete/restore now propagates to every viewer live, instead of waiting out the 30s
staleTime. Following the files pattern — but the honest, non-hacky version factors the two into one shared implementation rather than leaving two ~150-line copies.setupWorkspaceInvalidationRoom(server) anduseWorkspaceInvalidationRoom(client) — the presence-free, workspace-scoped live-list room. Files and tables now both bind to it, so they can't drift; event and room names derive from the room type. This replaces the standalone workspace-files handler + hook (net: the refactor is less code than the pre-existing files-only version plus a tables copy would have been).ROOM_TYPES.WORKSPACE_TABLES+ its authz resolver (workspace-id-addressed, reuses the workspace resolver like workspace-files).notifyWorkspaceTablesChangedfires fromcreateTable/renameTable/moveTableToFolder/deleteTable/restoreTable, so it covers both the HTTP routes and copilot (which calls the service directly). Each call is gated on a genuine mutation./api/workspace-tables-changedendpoint; hook wired into the tables page.Scope note: table folder create/rename/delete goes through the shared generic folders API and is a clean, separate follow-up (table CRUD — including moves — is fully covered here).
Type of Change
Testing
Tested manually. Consolidated the handler test into one suite run against both room types (files + tables), so the shared impl is covered for each. Full gate suite green: realtime + sim typecheck, realtime 235 tests, sim files/tables/hooks/table-service 1180 tests, api-validation, monorepo-boundaries, realtime-prune, lint.
Checklist