Repository navigation
feat(group-chat): add phone fold handle and quit-when-idle pill to room composer - #1958
reachrazamair wants to merge 1 commit into
Conversation
…om composer
Step 7 of the Group Chat composer parity plan (rows 52 and 50).
Phone fold:
- Re-export the session-free PhoneComposerHandle from ChatComposer/index.ts.
- GroupChatInput exports GROUP_CHAT_PHONE_COMPOSER_COLLAPSED_KEY
('phone.groupChatComposer.collapsed') and tracks its fold with
usePersistedToggle(GROUP_CHAT_PHONE_COMPOSER_COLLAPSED_KEY, true), starting
folded on a phone and persisting separately from AI chat's
PHONE_COMPOSER_COLLAPSED_KEY.
- Every hook in GroupChatInput runs before the folded branch, so the draft,
staged images, voice state and autosize survive folding and unfolding, and
toastAvoidRef wraps the folded handle so toasts still clear it.
Quit-when-idle pill:
- Render QuitWhenIdleIndicator at the top of the unfolded room composer,
matching InputArea. useQuitWhenIdle -> collectActiveOperations() already
counts busy group chats (moderator thinking or any participant working) via
getBusyGroupChatIds, so no change to the quit watcher is needed.
Group Chat behaviour changes:
- Phone: the room composer starts folded behind PhoneComposerHandle (remembered
under phone.groupChatComposer.collapsed). While folded, the handle shows a
pulsing warning dot when the room is busy and a pencil icon when unsent text
or staged images are waiting. Tap or swipe up reveals the composer; tap or
swipe down on the top handle folds it back.
- Desktop and phone (unfolded): when Quit When Idle is armed, the "Quitting
When All Operations Finish" pill with its Cancel button appears at the top of
the room composer.
- Desktop with no quit armed is unchanged.
CLI-UI-PARITY.md records the phone composer fold keys and Quit When Idle under
Not mirrored by design, and WEB-MOBILE.md updates the phone composer row.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review: 2
Please check the settings in the CodeRabbit UI or the
|
[Medium impact] The PR changes Group Chat composer behavior on phones and adds a quit-status view to room composers. The PR appears safe to merge, with a non-blocking draft-height issue on phones. Findings
SummaryAdds a remembered phone fold handle and the existing quit-when-idle pill to the Group Chat composer.
Reviews (1) · Last reviewed commit: "feat(group-chat): add phone fold handle ..." · Reviewed by Greptile |
| if (phone && composerFold.value) { | ||
| return ( | ||
| <div ref={toastAvoidRef}> | ||
| <PhoneComposerHandle | ||
| theme={theme} | ||
| collapsed | ||
| onToggle={composerFold.toggle} | ||
| busy={isBusy} | ||
| hasDraft={phoneHandleHasDraft} | ||
| /> | ||
| </div> | ||
| ); |
There was a problem hiding this comment.
Folding and reopening a multiline draft leaves the textarea at its single-row height until the user edits it. The fold removes the textarea, but reopening changes none of useAutosizeTextarea's dependencies, so the new textarea never gets measured. Saved multiline drafts first opened from the default folded state have the same problem.
Pass the fold state through resetKey so reopening measures the draft again, and add a test for this case.
Summary
Step 7 of the Group Chat composer parity plan (
Plans/group-chat-composer-parity.md), covering rows 52 (the phone fold handle, completing what step 5 started) and 50 (the app-wide quit-when-idle indicator). Stacked on #1952 (refactor/composer-textarea); review that first.PhoneComposerHandle+usePersistedToggle):PhoneComposerHandlefromsrc/renderer/components/ChatComposer/index.ts.GroupChatInputexportsGROUP_CHAT_PHONE_COMPOSER_COLLAPSED_KEY = 'phone.groupChatComposer.collapsed'and callsusePersistedToggle(GROUP_CHAT_PHONE_COMPOSER_COLLAPSED_KEY, true).usePhoneLayout()), the room composer starts folded behindPhoneComposerHandleand remembers its state across room switches and reloads independently of AI chat'sPHONE_COMPOSER_COLLAPSED_KEY.busy={state !== 'idle'}) and the draft pencil (hasDraft={message.trim().length > 0 || stagedImages.length > 0}), wrapped intoastAvoidRefso toasts still clear the handle. All hooks (useDraftPersistence,useVoiceInput,useAutosizeTextarea,useMentionPicker) run above the fold branch, so the draft, staged images, voice state and autosize survive folding and unfolding.px-3 pb-3 pt-0, matchingInputArea).QuitWhenIdleIndicator):<QuitWhenIdleIndicator theme={theme} />at the top of the unfolded room composer, matchingInputArea.useQuitWhenIdle->collectActiveOperations()already counts busy group chats viagetBusyGroupChatIds(gcStore.groupChats, gcStore)(moderator thinking or any participant working, across both the active room and background rooms), so the pill's "Quitting When All Operations Finish" label is accurate in a room with no change to the quit watcher.Room behaviour changes
PhoneComposerHandle(remembered underphone.groupChatComposer.collapsed, separate from AI chat'sphone.composer.collapsed). Tap or swipe up reveals the composer; tap or swipe down on the top handle folds it back. While folded, the handle shows a pulsing warning dot when the room is busy (moderator-thinkingoragent-working) and a pencil icon when unsent text or staged images are waiting.QuitWhenIdleIndicatorreturnsnull, andPhoneComposerHandleis gated onusePhoneLayout()).CLI parity and docs
docs/agent-guides/CLI-UI-PARITY.md: under Not mirrored by design, extends the rendererlocalStorageview-preferences entry to cover the phone composer fold keys (phone.composer.collapsedandphone.groupChatComposer.collapsed) and adds an entry for Quit When Idle (armed from the native desktop quit-confirmation modal; read-only indicator with Cancel).docs/agent-guides/WEB-MOBILE.md: updates theComposerrow in the phone layout table to cover bothInputAreaandGroupChatInputand their per-surfacelocalStoragekeys.Not in this step
ChatComposershell yet. That is step 8.useQuitWhenIdleorcollectActiveOperations. Both already wait for busy rooms and moderators.Test plan
npm run lintnpm run lint:eslintnpm run docs:verifynpx vitest runon the stack's test set (40 files, 971 tests):composerKeyDown.test.ts,GroupChatInput.test.tsx,GroupChatInput.toolbar.test.tsx,useInputKeyDown.test.ts,useInputKeyDown.focus.test.tsx,useMainKeyboardHandler.test.ts,useInputHandlers.test.ts,InputArea.test.tsx,components/InputArea/,components/ChatComposer/,ui/PhoneBottomSheet.test.tsx,FilePreview/FilePreviewHeaderPhone.test.tsx,useVoiceInput.test.tsGroupChatInput.toolbar.test.tsx:phone.groupChatComposer.collapsedindependently of AI chat'sphone.composer.collapsed.phone-composer-handle-busyandphone-composer-handle-draft(including image-only drafts).QuitWhenIdleIndicatorrenders in a room only whileuseQuitWhenIdleStoreis armed, and clicking Cancel disarms it.