Skip to content

🗂️ feat: Rework the Projects Dashboard, Sidebar and Scoped Composer - #14866

Open
berry-13 wants to merge 20 commits into
devfrom
redesign/projects-dashboard-navbar
Open

🗂️ feat: Rework the Projects Dashboard, Sidebar and Scoped Composer#14866
berry-13 wants to merge 20 commits into
devfrom
redesign/projects-dashboard-navbar

Conversation

@berry-13

Copy link
Copy Markdown
Collaborator

Summary

Reworks the Projects surfaces so the dashboard, the workspace, the sidebar section and the project-scoped composer read as one feature, and fixes the bugs that showed up while going through them.

Dashboard and workspace. Both sat on bg-surface-primary at different max widths, so moving between them shifted the content and the shade did not match the rest of the app. Both are now bg-presentation at max-w-6xl. Project and chat cards gain a border, since colour alone separated them from the background and that separation is thin in light mode. The translucent blurred headers become opaque, and the scale-on-press transforms are dropped. In the workspace the edit and delete actions move out of the heading row into their own group, so a long project name no longer pushes them around.

Sidebar section. The header duplicated the project count and the New Project action already on the dashboard, and spent a row on a chevron button separate from its label. It collapses to a single label toggle plus an All Projects action. The per-project new chat action becomes a real link to the project-scoped URL, so it can be middle-clicked and opened in a new tab, and row actions stay visible on devices without hover, where an action that only appears on hover cannot be reached.

Project scope. Starting a chat from a project set chatProjectId on the draft but left the URL unscoped, so a reload dropped the project. Both entry points now navigate to the project-scoped URL. The scope chip moves from a floating row above the composer to the first row inside the composer border, where it reads as part of the input rather than an unrelated control.

Change project dialog. It used a bare select, so picking a project meant scrolling an unsearchable native list capped at the default page of 25. It now uses the searchable ControlCombobox, requests the full first page, and disables Save until the selection actually differs. Project search also matches descriptions, not just names.

Project workspace chats gain the overflow menu the sidebar already has: change project, remove from project, delete.

The commits are split so each is reviewable on its own; the two fix: commits at the end are defects found during browser verification.

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Testing

Verified in the browser against a real backend, in both light and dark mode: created a project, started a project-scoped chat and confirmed ?projectId lands in the URL and survives a reload, opened the composer chip's project picker, assigned a conversation through the Change project dialog (including typing in its search field, which is the case the portal prop exists for), searched a project by a term that only appears in its description, and exercised the new chat-row overflow menu in the workspace.

Two defects were found and fixed this way: starting a project chat did not put the project in the URL, and closing the Ariakit menu in the same handler that opened the Change project dialog dismissed the dialog before paint, so the action did nothing.

ControlCombobox gained popoverClassName, matchTriggerWidth, gutter and portal. All four default to current behaviour, so the five existing comboboxes are untouched; portal in particular stays true, because turning it off inside a scrollable dialog would clip the list for the Anthropic and Bedrock preset settings. New tests pin both the preserved default and the opt-in.

Test Configuration:

npx eslint <changed files>                      # clean
cd client && npx tsc --noEmit                   # clean
cd packages/client && npx tsc --noEmit          # clean
cd client && npx jest src/components/Conversations src/components/Chat/__tests__/ChatView.spec.tsx
                                                # 6 suites, 38 tests passed
cd packages/client && npx jest ControlCombobox  # 10 tests passed
cd packages/data-schemas && npx jest chatProject # 9 tests passed

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes

Give /projects a sticky navbar, quieter search/sort toolbar, and
folder-style cards. Drop the create-dialog close control, restyle
the sidebar Projects row, and align the workspace with the same
layout language.
Add a shared edit dialog so a project can be renamed and given a
description from the workspace or the sidebar menu. The create flow
already stored descriptions; this is the matching update path.
Extract the project delete confirmation into a shared dialog and
expose it on the workspace header so deleting no longer requires
the sidebar menu.
Give dashboard cards a more-options menu that opens the same edit
and delete dialogs as the workspace, so those actions are not
workspace-only.
Project search only matched the name, so a project found by its
description was invisible in the sidebar and the projects dashboard.
Match the escaped search term against name or description.
The popover always matched the trigger width, sat 4px from it and used
the same enter animation, which is wrong for a pill-shaped trigger in a
composer and for a full-width field in a dialog.

Add popoverClassName, matchTriggerWidth, gutter and portal so a consumer
can opt out of each. All four keep the current behaviour by default, so
existing comboboxes are unchanged; portal in particular stays true, as
turning it off inside a scrollable dialog would clip the list.
areConversationListItemFieldsEqual left pinned out of its comparison, so
a row memoised on it kept rendering the stale pin state until some other
tracked field changed.
Starting a chat from the project workspace set chatProjectId on the
draft but left the URL on the unscoped route, so a reload or a refresh
of the route dropped the project. Navigate to the project-scoped new
chat URL alongside the draft.
The chip floated above the composer as a separate row, which read as an
unrelated control and pushed the conversation starters down. Render it
inside the composer border as the first row instead, and pass the
project through ChatForm so the memoised form still controls it.

The remove button no longer fades in on hover, since a control that only
appears on hover is unreachable by touch. Its popover opens upward with
a matching bottom-origin animation that honours reduced motion.
The dialog used a bare select, so picking a project meant scrolling an
unsearchable native list capped at the default page of 25. Use the
searchable ControlCombobox, request the full first page, and disable
Save until the selection actually differs from the current project.

The combobox opts out of portalling so its search field sits inside the
dialog's focus trap and can be typed in, and the dialog is
overflow-visible so the list is not clipped.

Unassigning now lives on the menu's own Remove From Project action, so
the dialog no longer needs an empty option. Returning focus to the menu
button rather than the menu item fixes focus being lost on close, since
the item unmounts with the menu.
Chats in a project workspace could only be opened. Managing one meant
finding it again in the sidebar, so add the same actions to the row:
change project, remove from project, and delete.

The row becomes a card matching the project cards, and the endpoint icon
is rendered at landing size rather than in a tinted tile. Its memo
comparison now uses areConversationListItemFieldsEqual, since the render
props comparison ignored fields the row displays.
The section header duplicated the projects count and the New Project
action already on the dashboard, and spent a row on a chevron button
separate from its label. Collapse it to a single label toggle with an
All Projects action, and drop the per-project count that was hidden on
hover anyway.

The new chat action becomes a real link to the project-scoped URL, so it
can be middle-clicked and opened in a new tab, and modified clicks fall
through to the browser. On the new chat route it commits ?projectId
synchronously, because a deferred search param update lets ChatRoute see
a project-scoped draft on an unscoped URL and wipe it.

Row actions stay visible on devices without hover, where an action that
appears on hover cannot be reached.
The dashboard and the workspace sat on bg-surface-primary at different
max widths, so moving between them shifted the content and the shade did
not match the rest of the app. Put both on bg-presentation at max-w-6xl.

Project and chat cards gain a border, since colour alone separated them
from the background and that separation is thin in light mode. The
translucent blurred headers become opaque, and the scale-on-press
transforms are dropped.

In the workspace the edit and delete actions move out of the heading row
into their own group, so a long project name no longer pushes them
around.
Closing the Ariakit menu in the same handler that opens the dialog made
the menu's own dismissal land on the freshly mounted Radix dialog, which
closed it again before paint, so Change project did nothing.

Leave the menu close to the dialog, which already receives setMenuOpen
and closes it once the assignment succeeds, matching the share and
delete handlers beside it.
Copilot AI lite review requested due to automatic review settings August 15, 2026 06:12

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ee8931ba03

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/components/Projects/ProjectChatOptions.tsx Outdated
Comment thread client/src/components/Projects/ProjectsView.tsx Outdated
Comment thread client/src/style.css Outdated
Comment thread client/src/components/Conversations/ProjectsSection.tsx
Comment thread client/src/components/Projects/ProjectCreateDialog.tsx

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR reworks the Projects feature surfaces (dashboard, workspace, sidebar section, and project-scoped composer) so they behave and look like a cohesive flow, while addressing project-scoping/navigation and project assignment UX limitations across the app.

Changes:

  • Backend: project search now matches both project name and description, with updated schema-method test coverage.
  • UI/UX: Projects dashboard/workspace layouts are unified (presentation background + max width), cards/headers/actions are reworked, and project-scoped “new chat” navigation now correctly scopes the URL.
  • Components: ControlCombobox gains configurable popover behaviors (portal/sizing/gutter/classes) with tests; project CRUD dialogs and project chat overflow menu are introduced/expanded.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/data-schemas/src/methods/chatProject.ts Extends project search filtering to include description via $or.
packages/data-schemas/src/methods/chatProject.spec.ts Adds coverage for name/description search behavior.
packages/client/src/components/ControlCombobox.tsx Adds popover configuration props (portal, sizing, gutter, custom class).
packages/client/src/components/ControlCombobox.spec.tsx Adds tests for search filtering and portal-in-dialog behavior.
client/src/style.css Adds a bottom-origin popover animation class with reduced-motion handling.
client/src/locales/en/translation.json Adds new UI strings for projects (counts, actions, empty states, etc.).
client/src/components/Projects/ProjectWorkspace.tsx Unifies workspace layout/styling, adds edit/delete actions, and fixes project-scoped new-chat URL navigation.
client/src/components/Projects/ProjectsView.tsx Redesigns the projects dashboard: navbar, cards, skeletons, empty/search states, sorting UI.
client/src/components/Projects/ProjectsNavBar.tsx New sticky navbar for the projects dashboard with responsive sidebar trigger.
client/src/components/Projects/ProjectEditDialog.tsx New project edit dialog (name + description) using shared dialog primitives.
client/src/components/Projects/ProjectDeleteDialog.tsx New project delete confirmation dialog with redirect handling.
client/src/components/Projects/ProjectCreateDialog.tsx Adds optional description on create and updates dialog structure/styling.
client/src/components/Projects/ProjectChatOptions.tsx New overflow menu for project workspace chat rows (change/remove/delete).
client/src/components/Projects/ProjectChatList.tsx Updates project chat list row UI and integrates the new overflow menu.
client/src/components/Conversations/utils.ts Expands conversation equality comparison to include pinned.
client/src/components/Conversations/ProjectsSection.tsx Reworks sidebar Projects section: simplified header/actions, accessible always-available row actions, project-scoped new chat link behavior.
client/src/components/Conversations/ConvoOptions/ProjectButton.tsx Replaces native select with searchable ControlCombobox, increases initial project page size, and disables save when unchanged.
client/src/components/Conversations/ConvoOptions/ConvoOptions.tsx Adjusts dialog trigger refs for the “Change project” dialog flow.
client/src/components/Chat/ProjectLandingChip.tsx Moves project scope control into the composer and customizes combobox popover presentation.
client/src/components/Chat/Input/ChatForm.tsx Renders the project scope chip inside the composer when on a project-scoped landing.
client/src/components/Chat/ChatView.tsx Passes project context down into ChatForm instead of rendering the chip above it.
client/src/components/Chat/tests/ChatView.spec.tsx Updates mocks to reflect chip relocation into ChatForm.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread client/src/components/Projects/ProjectEditDialog.tsx
Comment thread client/src/components/Projects/ProjectEditDialog.tsx
Hiding the Ariakit menu in the same handler that opens Change project or
Delete restores focus to the menu trigger, which the dialog mounting
alongside it reads as an outside interaction and closes on, so the
action could do nothing.

Both dialogs already receive setIsMenuOpen and close the menu once they
finish, so leave the close to them, as the conversation menu does.
Collapse hides its children with CSS and inert rather than unmounting
them, so every project row's chat query ran on sidebar load, up to one
request per project, even with the whole section collapsed.

Gate the query on the row's expanded state. React Query keeps what it
already fetched, so reopening a row is still instant.
ControlCombobox owns its popover animations in AnimatePopover.css, so
the upward variant it needs belongs there rather than in the
application stylesheet, where the control's appearance would diverge
from the package that ships it.

The app already loads the package stylesheet, so the animation resolves
the same way the existing variants do.
The dialogs accepted any length and reported success, while the
persistence layer trimmed names to 100 and descriptions to 1000
characters, so reopening a project revealed text had been dropped with
no warning.

Share both limits from data-provider and cap the inputs at them, so the
fields stop where the server would have cut them and the rule has one
definition instead of the three it had.
The dashboard counted the projects fetched so far, so an account with
more than one page read as exactly one page's worth and the supposed
total grew with each Load more.

Show the loaded count as a lower bound while another page exists.
@berry-13

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 1c3f3dbf97

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sort the delete dialog's imports to the repository order, and drop the
three English keys this branch orphaned: the sidebar menu now says Edit
project, the dashboard labels its own sort control, and the change
project dialog no longer offers an Unassigned option now that removal
lives on the menu.
@berry-13
berry-13 requested a review from danny-avila August 15, 2026 16:51
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.

2 participants