Conversation
…dialog Agent-Logs-Url: https://github.com/lakubuDavid/mini-cms/sessions/4992ee7a-68f9-4ba9-861c-95ad5c59eeb7 Co-authored-by: lakubuDavid <32282902+lakubuDavid@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Fixes several dashboard UX/state issues: adds a real workspace dropdown in the sidebar, stabilizes project-selection effects and preserves router history state when updating query params, and prevents the create-project dialog from getting stuck pending on server errors.
Changes:
- Split the sidebar workspace row into a link area + chevron-triggered dropdown.
- Fix dashboard project-selection
useEffectdependencies and preservewindow.history.statewhen callingreplaceState/dispatchingpopstate. - Wrap create-project flow in
try/catch/finallyto always clear pending state and surface errors.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| apps/web/src/routes/dashboard/route.tsx | Stabilizes URL/query handling and adds a workspace dropdown menu UI in the sidebar. |
| apps/web/src/routes/dashboard/index.tsx | Improves create-project dialog reliability by handling server errors and always resetting pending state. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| className="fixed inset-0 z-40" | ||
| onClick={() => setWorkspaceOpen(false)} | ||
| /> | ||
| <div className="absolute bottom-full left-0 z-50 mb-2 w-full rounded-xl border border-stone-200 bg-white p-3 shadow-lg dark:border-stone-700 dark:bg-stone-900"> |
There was a problem hiding this comment.
The workspace dropdown backdrop only closes on click; there’s no keyboard handling (e.g., Escape) so keyboard users can get stuck with the menu open. Consider matching the pattern used in apps/web/src/routes/dashboard/api-keys.tsx:549-554 by adding an onKeyDown Escape handler (and/or a document keydown listener while open) so the menu can be dismissed without a pointer.
| <div className="absolute bottom-full left-0 z-50 mb-2 w-full rounded-xl border border-stone-200 bg-white p-3 shadow-lg dark:border-stone-700 dark:bg-stone-900"> | |
| <div | |
| className="absolute bottom-full left-0 z-50 mb-2 w-full rounded-xl border border-stone-200 bg-white p-3 shadow-lg dark:border-stone-700 dark:bg-stone-900" | |
| onKeyDown={(event) => { | |
| if (event.key === "Escape") { | |
| setWorkspaceOpen(false); | |
| } | |
| }} | |
| > |
| <button | ||
| type="button" | ||
| onClick={() => setWorkspaceOpen(!workspaceOpen)} | ||
| aria-label="Workspace menu" | ||
| className="flex items-center justify-center px-2.5 py-2 text-stone-400 transition hover:bg-stone-100 hover:text-stone-600 dark:hover:bg-stone-800 dark:hover:text-stone-300 border-l border-stone-200 dark:border-stone-800" | ||
| > | ||
| <ChevronDown className="h-4 w-4" /> | ||
| </button> |
There was a problem hiding this comment.
New workspace dropdown behavior isn’t covered by existing Playwright e2e tests (no tests reference the “Workspace menu” button / “Workspace settings” entry). Adding a regression test that opens the dropdown via the chevron button and verifies the “Workspace settings” link navigates correctly would help prevent future sidebar regressions.
| try { | ||
| const project = await createProjectServerFn({ | ||
| data: { name, slug }, | ||
| }); | ||
|
|
||
| setPending(false); | ||
| if (!project) { | ||
| setError("Unable to create project. Please try again."); | ||
| return; | ||
| } | ||
|
|
||
| if (!project) { | ||
| setError("Unable to create project. Please try again."); | ||
| return; | ||
| setName(""); | ||
| setSlug(""); | ||
| setOpen(false); | ||
| props.onCreated(); | ||
| } catch (cause) { | ||
| setError( | ||
| cause instanceof Error | ||
| ? cause.message | ||
| : "Unable to create project. Please try again.", | ||
| ); | ||
| } finally { | ||
| setPending(false); | ||
| } |
There was a problem hiding this comment.
The create-project error-handling path (server throws -> error message shown + pending resets) isn’t exercised by automated tests. Since the repo already has Playwright e2e coverage, adding a test that forces createProjectServerFn to fail (or intercepts the network request) and asserts the dialog exits the “Creating…” state and displays the error would prevent regressions.
The sidebar workspace button had no actual dropdown — the entire element (including
ChevronDown) was a single<Link>navigating to the workspace page. Project fetching on the dashboard was broken by auseEffectdependency bug and incorrecthistory.replaceStateusage. The create-project dialog silently got stuck in a pending state on server errors.Sidebar workspace: split button and dropdown
The workspace row is now split into two interactive zones within a shared bordered container:
<Link to="/dashboard/workspace">ChevronDown) → toggles a floating dropdown menu (mirrors the profile-menu pattern) with a "Workspace settings" entryProject fetching: fix
useEffectdependency andreplaceStatestate losscurrentSearchwasnew URLSearchParams(window.location.search)computed inline — a new object reference on every render — causinguseEffectto fire on every render. Replaced withrawSearch(plain string):replaceStatewas called with{}as the state argument, wiping TanStack Router's stored history state and breaking subsequent route reads. Fixed to preserve the existing state:Path comparison now normalises trailing slashes (
pathname.replace(/\/$/, "")) so/dashboard/matches the same conditions as/dashboard.Create-project dialog: add
try/catch/finallycreateProjectServerFnalways re-throws on failure. Without atry/catch,setPending(false)was never reached, leaving the dialog stuck in "Creating…" with no visible error. Wrapped intry/catch/finally—finallyalways resets pending state;catchsurfaces the server error message.