improvement(url-state): use nuqs setters and derive state instead of mirroring it - #6486
Conversation
…mirroring it
Wave 1 of a URL-state audit sweep.
- files: replace the last hand-built same-path query mutation with the nuqs
group setter, which no longer drops shareFileId/search/type/size/uploaded-by/sort/dir
- suspense: give six page entries their co-located loading.tsx skeleton
instead of fallback={null}
- invite: derive isNewUser/urlError/token during render so the invitation
query key is correct on first commit
- resume: derive selectedStatus/queuePosition from the query cache the
mutation already writes
- verify, logs, terminal: delete dead and duplicate state
- rules: document same-path router.replace as a query mutation, and the
loading.tsx-as-Suspense-fallback convention
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview Files strips the ephemeral Page entries that use nuqs ( Invite derives Resume reads Smaller cleanups: verify resend countdown without extra disabled state; logs search hook no longer accepts Reviewed by Cursor Bugbot for commit c99f560. Configure here. |
Greptile SummaryThe PR replaces mirrored URL and query-cache state with derived values, preserves file query parameters through nuqs setters, and adds route loading skeletons as Suspense fallbacks.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/sim/app/invite/[id]/invite.tsx | The revised token-resolution gate prevents the previously reported tokenless initial request and redundant invitation cache entry. |
| apps/sim/app/workspace/[workspaceId]/files/files.tsx | The nuqs group setter removes only the new parameter while preserving the remaining file URL state. |
| apps/sim/app/(interfaces)/resume/[workflowId]/[executionId]/resume-page-client.tsx | Resume status and queue position now derive from the query cache already updated by the mutation. |
| apps/sim/app/(auth)/verify/verify-content.tsx | Resend availability now derives directly from the countdown and loading state. |
| apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/hooks/use-terminal-filters.ts | Terminal sorting now stores only the mutable direction while retaining the existing ordering behavior. |
Reviews (2): Last reviewed commit: "fix(invite): wait for the stored token b..." | Re-trigger Greptile
… query An authenticated user opening an invite without a token in the URL fired the query with a null token before the effect restored the session-stored one, producing a transient forbidden state and a redundant request under a second cache key. Distinguish 'storage not yet read' (undefined) from 'read and empty' (null) and gate the query on that.
|
@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 c99f560. Configure here.
…6488) Two gaps left by #6486. The query was gated on isTokenResolved but the loading state was not. With enabled: false React Query still reports success when the key already holds data, so a cached null-token entry made isPending false and rendered the accept UI for one frame before the effect applied the stored token. Reachable only on a client-side remount after a tokenless fetch already succeeded. An empty ?token= also stopped falling back to storage: searchParams.get returns '' which is not null, so token became '' where the pre-#6486 truthiness check had read sessionStorage. Normalize to null at the source.
Summary
files.tsxwith the existing nuqs group setter — the oldrouter.replacere-serialized the path by hand and silently droppedshareFileId,search,type,size,uploaded-by,sort, anddirloading.tsxskeleton instead offallback={null}, so a nuqs suspend no longer flashes a blank frameisNewUser/urlError/tokenduring render in the invite flow —tokenin particular now lands in the invitation query key on the first commit, instead of refetching under a second key when the session cache is warmselectedStatus/queuePositionon the resume page from the query cache the mutation already writes to, instead of duplicating it into local state.claude/rules/sim-url-state.md: a same-pathrouter.replaceis a query mutation (not a navigation), and a route'sloading.tsxdefault export is the correct<Suspense>fallbackFound by a codebase-wide audit against
.claude/rules/sim-url-state.mdand theyou-might-not-need-stateguidance. nuqs adoption is already strong — 28search-params.tsfiles, zero hand-rolled debounced search, zero hand-rolled sort params — so this wave is the remaining mechanical tail. Later waves cover the judgment calls (logsviewModeto the URL, resumecontextIddeep-linking, wire-key renames).Type of Change
Testing
bun run type-check,bun run lint:check(23/23), andvitest run app/invite app/(auth)(21 tests) all pass.Every change is behavior-neutral or a strict improvement. Three intentional deltas:
files.tsxnow strips onlynewrather than rebuilding the path, so a link like?new=1&shareFileId=Xkeeps the share dialog open where it previously closed itverify-content.tsxdrops a one-frame window where the Resend link rendered disabled atcountdown === 0urlErrornow clears if?error=is removed; no code path does that while mounted, so it is unobservableNot yet exercised in a browser — the
filesnew-flag strip, the six Suspense fallbacks, and the resume status badge are visual paths worth a manual pass.Checklist