Skip to content

improvement(url-state): use nuqs setters and derive state instead of mirroring it - #6486

Merged
waleedlatif1 merged 2 commits into
stagingfrom
worktree-url-state-audit
Aug 10, 2026
Merged

improvement(url-state): use nuqs setters and derive state instead of mirroring it#6486
waleedlatif1 merged 2 commits into
stagingfrom
worktree-url-state-audit

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Replaced the last hand-built same-path query mutation in files.tsx with the existing nuqs group setter — the old router.replace re-serialized the path by hand and silently dropped shareFileId, search, type, size, uploaded-by, sort, and dir
  • Gave six page entries their co-located loading.tsx skeleton instead of fallback={null}, so a nuqs suspend no longer flashes a blank frame
  • Derived isNewUser / urlError / token during render in the invite flow — token in particular now lands in the invitation query key on the first commit, instead of refetching under a second key when the session cache is warm
  • Derived selectedStatus / queuePosition on the resume page from the query cache the mutation already writes to, instead of duplicating it into local state
  • Deleted dead and duplicate state in verify, logs search, and the terminal sort config
  • Documented two patterns in .claude/rules/sim-url-state.md: a same-path router.replace is a query mutation (not a navigation), and a route's loading.tsx default export is the correct <Suspense> fallback

Found by a codebase-wide audit against .claude/rules/sim-url-state.md and the you-might-not-need-state guidance. nuqs adoption is already strong — 28 search-params.ts files, zero hand-rolled debounced search, zero hand-rolled sort params — so this wave is the remaining mechanical tail. Later waves cover the judgment calls (logs viewMode to the URL, resume contextId deep-linking, wire-key renames).

Type of Change

  • Bug fix
  • Improvement

Testing

bun run type-check, bun run lint:check (23/23), and vitest run app/invite app/(auth) (21 tests) all pass.

Every change is behavior-neutral or a strict improvement. Three intentional deltas:

  • files.tsx now strips only new rather than rebuilding the path, so a link like ?new=1&shareFileId=X keeps the share dialog open where it previously closed it
  • verify-content.tsx drops a one-frame window where the Resend link rendered disabled at countdown === 0
  • invite urlError now clears if ?error= is removed; no code path does that while mounted, so it is unobservable

Not yet exercised in a browser — the files new-flag strip, the six Suspense fallbacks, and the resume status badge are visual paths worth a manual pass.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…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
@vercel

vercel Bot commented Aug 10, 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 Aug 10, 2026 6:12am

Request Review

@cursor

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Most changes are mechanical state/URL hygiene and documented patterns; the files new param strip is a small intentional UX fix for preserved query params, with no auth or data-layer changes.

Overview
This PR finishes the nuqs / “you might not need state” tail from the url-state audit: fewer hand-built query mutations, real Suspense fallbacks, and less mirrored client state.

Files strips the ephemeral new flag with setFilesParams({ new: null }, { history: 'replace', scroll: false }) instead of rebuilding the path via router.replace, so other query params (e.g. shareFileId, filters) are not dropped.

Page entries that use nuqs (login, sso, invite, files, knowledge routes) now use each segment’s co-located loading.tsx as the <Suspense> fallback instead of fallback={null}, avoiding blank frames when useSearchParams suspends.

Invite derives token, isNewUser, and URL error during render so the invitation query key is correct on the first commit; session storage only backs the token when it’s missing from the query.

Resume reads selectedStatus and queuePosition from selectedDetail (and React Query cache updates on resume) instead of duplicating them in useState and syncing in effects.

Smaller cleanups: verify resend countdown without extra disabled state; logs search hook no longer accepts initialQuery; workflow terminal sort is a single sortDirection (timestamp-only). .claude/rules/sim-url-state.md documents same-path query mutations vs navigation and the loading.tsx Suspense pattern.

Reviewed by Cursor Bugbot for commit c99f560. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The 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.

  • Resolves invite tokens before issuing the authenticated invitation query.
  • Derives resume status and queue position from the query cache.
  • Simplifies verification, log-search, and terminal filter state.
  • Preserves unrelated file query parameters when removing the new flag.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

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

Comment thread apps/sim/app/invite/[id]/invite.tsx Outdated
… 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.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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.

@waleedlatif1
waleedlatif1 merged commit 5bfcc67 into staging Aug 10, 2026
30 checks passed
@waleedlatif1
waleedlatif1 deleted the worktree-url-state-audit branch August 10, 2026 06:19
waleedlatif1 added a commit that referenced this pull request Aug 10, 2026
…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.
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