Skip to content

feat(site/src/pages/AgentsPage/components): drag chats onto project folders in the sidebar - #30795

Open
ibetitsmike wants to merge 30 commits into
mike/move-chats-menufrom
mike/move-chats-to-projects
Open

ibetitsmike wants to merge 30 commits into
mike/move-chats-menufrom
mike/move-chats-to-projects

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

In the sidebar, the owner of a chat can now drag it onto a project folder to move it there, or onto Chats to remove it from its project, with the mouse or the keyboard.

Stack (moving chats between projects, bottom first):

  1. feat: move a chat family between projects in chatd #30893: the move in chatd
  2. feat: move chats between projects through the chat update API #30894: the chat update API takes project_id
  3. feat(site/src): move chats between projects from the chat menu #30895: Move to project in the chat menu
  4. This PR: drag a chat onto a project folder in the sidebar

Why: the menu from #30895 takes three clicks. Dragging a chat onto a folder is the direct way, and it uses the same mutation.

  • Only the root row of a chat that the menu could move is draggable: the owner's root chat while it and its subagents are idle and not archived, with the chat-projects experiment. Pinned chats keep their reorder drag and move through the menu.
  • While a chat is dragged, the targets it cannot move to are muted: its own folder, the folders of other organizations, and Chats for a chat that is already there or whose project did not load. A drop on a folder opens it, so the user sees the chat arrive.
  • Screen readers hear the chat title and the folder name during the drag, never an ID.
  • The sidebar no longer shows the organization name next to a folder whose name another organization also uses. The folder's accessible names, the drag announcements and the delete dialog still name it.

What to scrutinize: the drop rules in chats/projectDrag.ts and handleDragEnd() in ChatsPanel.tsx. Most of the ChatsPanel.tsx diff is indentation from the wider DndContext, so read it with whitespace hidden.

The drag preview of a chat over the Billing folder, which shows an outline

Pixel: ChatDraggedOverProjectFolder, ChatDroppedOnProjectFolder (the dropped chat in the folder that the drop opens), LooseChatDragMutesUnavailableTargets, ProjectChatDragMutesItsFolder, UnloadedProjectChatDragMutesChats and SameNamedProjects (two same-named folders with no organization text).

Testing

  • make pre-commit passes. Vitest passes on the 2 touched specs (74 tests), and the ChatsSidebar Storybook tests pass (89).
  • The drag tests check the request that a drop sends, or that it sends none, for keyboard and mouse drags onto folders and Chats. A node identity test fails when a row remounts, and closes its open menu, as its chat status changes.
  • Untested: the click guard after a drag, because jsdom has no layout.
  • Dogfood UAT on a deployment of the whole stack passed for the menu, the visibility rules, the busy 409, the API rules, the instructions of the next turn, live updates, drag and drop, the composer copy and the audit entry. It also read the drag live region: keyboard and mouse drags announce the chat title and the folder name.

Review record

  • frontend-review, frontend-deep-review, coder-frontend-review and 13 Codex rounds ran on the unsplit branch, which this PR still carries. Every thread is resolved.
  • Kept: the row wrapper is the drag handle (role="button"), as in SortableChatTreeNode for pinned rows. The mouse drag tests use fireEvent: with user-event's pointer API, React reports dnd-kit updates outside act and the drop sends no request.
  • Follow-ups: where focus goes after a row moves away, a split of ChatsPanel.tsx (846 lines), and one predicate that the menu and the drag share for the move rule.

Xum opened this PR on behalf of @ibetitsmike.

PATCH /api/v2/chats/{chat} now accepts project_id. A UUID moves an idle
root chat into a project of its owner and organization; uuid.Nil removes
it from its project. The project checks are the ones of chat creation,
now shared by validateChatProjectSelection.

The chatstate machine gains a SetProject transition, allowed only from
W, E0 and E1. SetFamilyProject locks the root first and then each
subagent chat, so a busy family returns 409 and the move never overlaps
a step. chatd publishes a project_change watch event for each family
member after the commit.
The chat menu (sidebar row, top bar and project page row) gets a "Move to
project" submenu for the owner of a root chat that is not archived, behind
the chat-projects experiment. It lists the projects of the chat's
organization from the project list the sidebar already loaded, marks the
current project, and ends with "Remove from project". While the chat or a
subagent runs, the submenu is off and shares the Archive agent hint.

moveChatToProject() updates the cached lists and the chat optimistically,
restores only project_id on failure, and refetches the lists when it
settles. project_change watch events update project_id in other tabs and
refetch the filtered lists, and the project page drops rows whose chat
moved to another project.

The new-chat composer no longer says that a chat cannot move later.
- Keep each sidebar row's wrapper mounted when the chat's drag eligibility
  changes, so a status change no longer remounts the row and closes its menu.
- Share one ChatDropArea for project folders and Chats, drawn as an outline.
- Read dnd-kit drag data through type guards instead of casts.
- Group projects with Object.groupBy instead of a module cache.
- Add stories for the Move to project submenu states and a drag over a folder.
- Tidy test fixtures, queries and comments.
…jects

- Add stories for an unfiled chat's submenu and the blocked menu item.
- Restore plain project fixture IDs in tests.
- Clarify comments on the project grouping, the blocked prop and drop lookup.
- Name the arrow-key check in the keyboard getter and drop a no-op class.
… root row to move a chat family

Subagent rows rendered inside the draggable wrapper of their root, so a
drag that started on a subagent row moved the root chat. The drag handle
is now the root row itself, and the subagent subtree stays outside it.
…d moves and drop folder opening

Assert the move failure toast still shows after the menu closes, assert a
drop opens its target folder, and stub the projects request in the row
remount test so it no longer reaches a real server.
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T21:14:33.512965Z 3f2a42d Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 649a0ad9b7

ℹ️ 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 site/src/api/queries/chats.ts
Comment thread site/src/pages/AgentsPage/components/ProjectPage/ProjectChatsList.test.tsx Outdated
…ed chat in the cache, not the DOM

FE1 leaves rendered presence to screenshots. The row menu test now checks
the move request and the project page's own list cache, and the new
ChatMovedToAnotherProject story shows that the page leaves out a cached
chat of another project.
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@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: fd48f30247

ℹ️ 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 site/src/api/queries/chatProjects.ts Outdated
Comment thread coderd/x/chatd/chatstate/transition.go
Comment thread coderd/exp_chats.go
… its project

A chat moved out of its project, or whose project was deleted, kept the
memory index the model saw there, while the memory tools were gone. A
root chat outside a project now has an empty index, so its next turn
start sends an update that removes those memories. Such a chat reads the
prompt only at turn start, the only step where that removal can be due.
Object.groupBy needs Chrome 117 and Safari 17.4, and the browserslist
supports Chrome 111 and Safari 16.4 with no polyfill, so the Move to
project menu threw on those browsers. lodash groupBy keeps the server
order of the projects.
syncMemoryIndex and memoryIndexMessage now call the loaded chat messages
history, and the doc comment says plainly when a chat outside a project
reads its prompt rows.
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@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: 7d14cffa6d

ℹ️ 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".

… drags by name

dnd-kit's default announcements read the draggable and droppable IDs, so
a screen reader heard "move:<id>" and "project:<id>" during the new
keyboard drag. The sidebar's DndContext now announces the chat title and
the folder name, and pin drags keep the defaults.
…ed" in the drag announcement

User-facing strings in site/src use "canceled". The drag test now reads
the dnd-kit live region by its status role instead of searching for
visually hidden text.
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@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: 310bf07153

ℹ️ 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 site/src/pages/AgentsPage/components/MoveToProjectMenuItems.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/MoveToProjectMenuItems.tsx Outdated
Comment thread site/src/pages/AgentsPage/components/ChatsSidebar/ChatsSidebar.test.tsx Outdated
…ithout Move to project in stories

The archived, shared and subagent menu cases asserted DOM absence in
Vitest, which the frontend contract (FE1) leaves to screenshots. Three
stories now open those menus with the chat-projects experiment on, and
the Vitest absence checks are removed.
…e rule above its three stories

The JSDoc on the first story became that story's description in Storybook, where "these menus" had no referent. A plain comment above the group keeps the rule out of a single story's docs.
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@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: 1fc564f8f0

ℹ️ 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 site/src/pages/AgentsPage/components/ChatsSidebar/ChatsSidebar.test.tsx Outdated
…ove after the menu closes

The refused-move test waited for the menu item to leave the DOM before it
checked the toast. The update now rejects only after the select, so the
test still shows that the toast outlives the menu without a DOM check.
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@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: 4d4bceaa99

ℹ️ 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 site/src/api/queries/chats.ts
…ange

A move keeps the chat's updated_at, so the watch merge takes project_id
from each project_change payload in arrival order. The server publishes
after it releases the root lock, so two quick moves can reach another
tab in reverse order, and the open chat then kept the older project in
its top bar and Move menu. The list caches refetched on project_change;
the chat entity did not.

The watch handler now refetches the open chat on project_change. Each
event first cancels an entity refetch in flight, and the server
publishes after commit, so the refetch after the last event reads the
committed project. A first fetch still in flight restarts, because
invalidation would reuse a request that may predate the move.

The archive tests and the new move tests share one mock of the watch
socket.
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@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: 1ac9da0de8

ℹ️ 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 site/src/api/queries/chats.ts
…ojects

# Conflicts:
#	site/src/pages/AgentsPage/AgentsPageLayout.test.tsx
…n Chats from moving a chat whose project did not load
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@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: ac557eba76

ℹ️ 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 site/src/pages/AgentsPage/components/ChatsSidebar/ChatsSidebar.stories.tsx Outdated
Comment thread site/src/pages/AgentsPage/AgentsPageLayout.tsx
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

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

Reviewed commit: c81a1707df

ℹ️ 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".

…ojects

# Conflicts:
#	site/src/pages/AgentsPage/components/ChatsSidebar/ChatsSidebar.stories.tsx
#	site/src/pages/AgentsPage/components/ChatsSidebar/chats/ChatsPanel.tsx
#	site/src/pages/AgentsPage/components/ChatsSidebar/chats/ProjectFolders.test.tsx
…nization name next to same-named project folders
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: cacfc9b3fc

ℹ️ 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".

This branch becomes the top layer of a stack. The merge takes the
lower layers, including their cleanups, and keeps this branch's
changes, so the PR diff is only the sidebar drag and drop.
…ose chat story fixture

The drag stories reuse one loose chat, the drop test helper loses an
unused default, and the drop label comment says accessible name: the
folder no longer shows the organization that the label can add.
@ibetitsmike
ibetitsmike changed the base branch from main to mike/move-chats-menu October 16, 2026 12:42
@ibetitsmike
ibetitsmike added this pull request to stack #30896 October 16, 2026 12:42
@ibetitsmike ibetitsmike changed the title feat: move chats between projects feat(site/src/pages/AgentsPage/components): drag chats onto project folders in the sidebar Oct 16, 2026
@ibetitsmike
ibetitsmike marked this pull request as ready for review October 16, 2026 14:00
@ibetitsmike
ibetitsmike requested a review from a team as a code owner October 16, 2026 14:00
@pr-queue-manager
pr-queue-manager Bot requested a review from jaaydenh October 16, 2026 14:24
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 3f2a42d740

ℹ️ 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".

This branch has not been deployed

No deployments
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