feat(desktop): space picker in the composer, and composer chrome cleanup - #77565
Conversation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J4jadVYefktsDCvLvGXDKP
Chip renders a div so its close button can nest legally, but the button behaviour underneath assumes a native button unless told otherwise, so it never bound Enter or Space. The chip took focus and then did nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J4jadVYefktsDCvLvGXDKP
|
😎 Merged successfully - details. |
|
React Doctor found 1 issue in 1 file · 1 error. Errors
Reviewed by React Doctor for commit |
Hoist #me above the starred spaces: the group inherited the name sort, so any starred space alphabetically ahead of it pushed the personal space down. Lead each group with its rule instead of trailing all but the last. The render callback counts only the groups base-ui keeps, so filtering the tail group away stranded a separator under the list. Gate the editor's right inset on the submit cluster existing. The observer's cleanup cannot clear the measured width, so a cluster that unmounts left its gutter behind. Hide the slash-command item when the editor registers no `/` extension, where it would have typed a bare slash and opened nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J4jadVYefktsDCvLvGXDKP
Prompt To Fix All With AI### Issue 1
products/desktop/packages/ui/src/features/canvas/components/WebsiteNewTask.tsx:135-137
**Space retargeting races task creation**
When a user selects another space while task creation is in flight, the picker navigates immediately but the pending submission retains the previous `onTaskCreated` callback, causing the completed task to be filed in the old space and redirecting the user away from the newly selected composer. Disable space selection while the task mutation is active.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "fix(desktop): correct space grouping and..." | Re-trigger Greptile |
|
Note 🤖 stamphog reviewed Greptile flagged a real, unresolved P1 race in the new space picker: WebsiteNewTask's onTaskCreated closes over the channel active at submit time and nothing disables SpaceSelect while a task creation is in flight, so switching spaces mid-submission files the finished task into the old space and navigates the user away from the space they just picked. Verified by reading the current file — the bug is present and unaddressed on the current head.
Gate mechanics and policy version
|
Retargeting mid-submit navigated away from the composer that owned the in-flight request, so the task filed into the space you left and the redirect pulled you off the one you picked. Every other chip in that row already closes over isCreatingTask; the picker now does too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J4jadVYefktsDCvLvGXDKP
…er-space-select # Conflicts: # products/desktop/packages/ui/src/features/task-detail/components/TaskInput.tsx
Problem
Two unrelated itches in the spaces composer, plus a few papercuts found on the way.
A new task always filed into whichever space you happened to open the composer from. There was no way to retarget it without backing out and starting again. The picker for this already existed in the static-spaces-sidebar prototype (#76355), but that PR is a large flag-gated rebuild of the whole sidebar and is not close to landing. The picker does not depend on any of it, so it is pulled out here on its own.
The rest is chrome. The model trigger sat a pixel below its neighbours, the channel
CONTEXT.mdwas disguised as a file attachment, and the slash-command surfaces had drifted off the design system.Changes
Space picker. A quill
Comboboxchip in the composer's selector row. Starred spaces (with#meleading) sit above the rest, searchable, since a project can carry hundreds. Picking one navigates to that space's own new-task route; the draft survives because it lives in the shared draft store.Decoupled from #76355: that version sorted starred spaces by the prototype sidebar's drag order and matched the personal space by name. This one derives everything from
useChannelsand keys offchannelType, so it carries none of the prototype's state.Composer chrome.
span, which builds a line box whose leading pushed them belowAttach,Modeand the history button. Measured 481.07 against 479.73; all four now share a top. The fix is in sharedPromptInput, so every composer with that toolbar gets it.CONTEXT.mdmoved out of the attachments row and pinned beside the send button as a quillChip. It is not a file you attached, it comes with the space and rides along with every send, so it no longer collapses to an extension square with its name hidden in a tooltip. The editor's right inset is now measured from that cluster rather than hardcoded, otherwise a long line runs under the chip.variant="default"and drop their carets.Slash commands.
Slash commandsitem in the attach menu, which writes/at the start of the composer. It inserts at position 1 and drops the caret at 2, leaving the editor in exactly the state typing/produces, so the existing suggestion plugin opens the list itself.role="listbox". They are nowItemMenuItemwithrole="option"andaria-selected, per the guidance inpackages/quill/packages/primitives/AGENTS.mdfor custom menu-like lists.weight="bold"to regular, whichGithubLogoneeded most.Note
Removing the chip treatment from skill chips also removes their hover ×. A skill is now deleted by selecting it and pressing backspace, which is what the destructive state signals.
How did you test this code?
Automated, run by me (Claude):
pnpm --filter @posthog/ui typecheck— cleanpnpm --filter @posthog/ui test— 306 files, 2545 tests, all passingbiome checkon every changed filehogli ci:preflight --strict— cleanI also drove the running dev app over CDP and verified: the picker renders, filters (
billto two results), marks the current space selected and navigates on pick; the measured editor padding tracks the context chip and reflows when it is removed; the attach menu's new item inserts/and opens the command list; the suggestion rows render as quill items with exactly onearia-selected.Two things I could not verify that way and would like a human to confirm:
No tests added. The changes are presentational or one-line wiring, and the parts worth testing (whether a tiptap suggestion plugin fires, whether Base UI binds Enter on a non-native button) are not reachable from jsdom, so a test would assert the wiring rather than the behavior.
Automatic notifications
Docs update
No docs update needed.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
I drove this; Claude (Claude Code, Opus 5) wrote most of it across an interactive session. Repo skills invoked:
/writing-user-facing-copybefore changing the context chip's label,/test-electron-appfor the CDP verification against the running app. The quill component choices came frompackages/quill/packages/primitives/AGENTS.md.A few decisions worth surfacing for review:
DropdownMenuand became aComboboxonce it was clear a project can have hundreds of spaces. It then had a real bug:Channelobjects were used as combobox items with a controlledvalue, which selects correctly once and then silently stops, because the channels query repolls and rebuilds its objects so identity matching fails. Items are now ids.Autocompleteand deliberately is not one. Base UI's Autocomplete owns a focused text input, its own filtering, its own highlight state and its own positioner. Here the tiptap plugin owns the query and keyboard and tippy owns positioning, and critically the caret has to stay in the editor, so an Autocomplete input holding focus would break typing in place. It was rebuilt with the menu-list primitives quill documents for exactly this case instead.nativeButton={false}on the context chip is not cosmetic. quill'sChiprenders a div soChipClosecan nest legally, and without that prop Base UI never binds Enter or Space, so the chip took focus and did nothing.The branch is named
posthog-code/composer-space-selectrather thandesktop/...because a remote branch named exactlydesktopblocksdesktop/*as a ref path.This holds several separable changes. I kept them together because they are all small and all in the same composer, but I am happy to split if a reviewer would rather see them apart.