fix(web): unify activity logs and composer banners - #8693
Conversation
Keep running status beside the composer and share layout across task, update, and stash banners. Remove duplicate plan log entries and the work/tool grouping split.
Keep the shared banner layout in its components and remove the separate stylesheet. Remove rendering-only tests that lock in labels, class names, and the selected status presentation.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
There was a problem hiding this comment.
UI consistency review of the composer banner migration. The new ComposerBanner primitive set, the ComposerBannerStack ordering/expansion rework, and the shared ScrollArea reuse all look sound; a few ownership and coverage issues below.
Posted via Macroscope — UI Consistency
| return placement === "inline" ? ( | ||
| row | ||
| ) : ( | ||
| <ComposerBanner.Root className="chat-composer-shoulder-tab chat-composer-tasks-tab"> |
There was a problem hiding this comment.
Same as the stash tab: chat-composer-tasks-tab has no remaining consumer now that shoulderTabReserve (which queried .chat-composer-tasks-tab) and the .chat-composer-shoulder-tab CSS block are gone. Keep the shoulder-tab marker that ChatView's group-has- selector still relies on.
| <ComposerBanner.Root className="chat-composer-shoulder-tab chat-composer-tasks-tab"> | |
| <ComposerBanner.Root className="chat-composer-shoulder-tab"> |
Posted via Macroscope — UI Consistency
| onDragLeaveCapture={onComposerMentionDragLeaveCapture} | ||
| onDropCapture={composerMentionDragHandlers.onDrop} | ||
| className={cn("mx-auto w-full min-w-0 max-w-3xl", hasShoulderTab && "pt-7")} | ||
| className="mx-auto w-full min-w-0 max-w-3xl" |
There was a problem hiding this comment.
--chat-composer-drawer-inset is now read but never defined. index.css lost the rule that declared it on [data-chat-composer-form="true"] / .chat-composer-drawer-slot / .chat-composer-top-drawer, yet ComposerCommandMenuLayer still reads it from this form element (ChatComposer.tsx:200) and now always falls through to the hardcoded 1.375. The real inset moved into ComposerBanner.Attachment as the literal w-[calc(100%-2.75rem)], so the two values can silently drift and misplace the command menu.
Smallest fix: re-declare the token on the owner that the lookup reads (and ideally derive the attachment width from it), or delete the now-dead getComputedStyle read and share one constant.
| className="mx-auto w-full min-w-0 max-w-3xl" | |
| className="mx-auto w-full min-w-0 max-w-3xl [--chat-composer-drawer-inset:1.375rem]" |
Posted via Macroscope — UI Consistency
| onClick={props.onToggleMenu} | ||
| <ComposerBanner.Root | ||
| width="content" | ||
| className="chat-composer-shoulder-tab chat-composer-stash-tab ml-auto" |
There was a problem hiding this comment.
chat-composer-stash-tab no longer has any consumer: the .chat-composer-shoulder-tab rule block was deleted from index.css and no selector, test, or JS query references the stash-specific class anymore. chat-composer-shoulder-tab is still needed (ChatView's group-has-[.chat-composer-shoulder-tab] padding hook), so keep only that one.
| className="chat-composer-shoulder-tab chat-composer-stash-tab ml-auto" | |
| className="chat-composer-shoulder-tab ml-auto" |
Posted via Macroscope — UI Consistency
| } | ||
|
|
||
| export function ComposerBannerStack({ className, items }: ComposerBannerStackProps) { | ||
| const [stackExpanded, setStackExpanded] = useState(false); |
There was a problem hiding this comment.
This change turns the stack from a CSS-only hover reveal into a real state machine — bannerPriority ordering, a focusable peek button, pointer/focus expansion, Escape-to-collapse — while ComposerBannerStack.test.tsx (plus the stash and tasks badge tests) is deleted and nothing replaces it. Ordering and expansion are exactly the behavior this check expects focused coverage for.
Consider a small render test asserting urgent → activity → notice ordering and that the peek button toggles aria-expanded / grid-rows-[1fr], with Escape collapsing and returning focus to the peek.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
UI consistency review
Two findings in the composer banner migration; the rest of the ComposerBanner extraction (shared surface, attachment geometry moved out of index.css, data-composer-banner-surface selector hooks) looks consistent with the shared primitives and preserves the glass/attachment ownership rules.
ComposerPendingUserInputPanel.tsx: the option buttons now run to the clipping edge of the permanentlyoverflow-hiddenCollapsiblePanel, shaving their focus ring on the trailing side (the removedpx-3 sm:px-4comment warned about exactly this).ComposerTasksBadge.tsx/ComposerStashMenu.tsx: the task and stash lists lost the explicitrole="list"/role="listitem"they used to carry, while the newul/liare rendered withdisplay: grid.
Posted via Macroscope — UI Consistency
| {expanded ? ( | ||
| <ComposerBanner.Scroll data-composer-tasks-scroll="true"> | ||
| <ComposerBanner.Children | ||
| render={<ul />} |
There was a problem hiding this comment.
The previous task list declared role="list" on the container and role="listitem" on each row. The replacement uses real ul/li, but both are rendered with display: grid by ComposerBanner.Children/ComposerBanner.Row, and Tailwind preflight also sets list-style: none — which drops the implicit list/listitem mapping in WebKit (and for grid-displayed li in Chromium). Net effect is that the count-bearing list semantics the old markup guaranteed are no longer reliable here or in the stash list (ComposerStashMenu.tsx:133).
Restoring them explicitly keeps the migration behavior-neutral:
| render={<ul />} | |
| render={<ul role="list" />} |
The row also needs render={<li role="listitem" />} (same for the stash entries) to keep the pairing intact.
Posted via Macroscope — UI Consistency
| <ComposerBanner.ToggleIcon expanded={!isCollapsed} /> | ||
| </ComposerBanner.Actions> | ||
| </CollapsibleTrigger> | ||
| <CollapsiblePanel> |
There was a problem hiding this comment.
CollapsiblePanel is permanently overflow-hidden (ui/collapsible.tsx), and the horizontal padding that used to keep the option buttons off that clip edge (px-3 sm:px-4, with the comment explaining why) moved into ComposerBanner.Body, which only pads the inline start. The w-full option buttons below now reach the panel's trailing edge, so their focus-visible:ring-1 is shaved off on that side.
Smallest fix is a trailing inset on the clipping element:
| <CollapsiblePanel> | |
| <CollapsiblePanel className="pe-1"> |
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix is ON, but a cloud agent failed to start.
Reviewed by Cursor Bugbot for commit 74d4ba6. Configure here.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This is a broad production UI refactor that changes the default composer, activity-log, banner-stacking, update-status, and accessibility behavior across existing flows. Unresolved concerns include shared geometry drift, deleted coverage for new interaction state, list semantics, and focus-ring clipping. You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
UI consistency review of the composer banner migration. Two findings, both about behavior/ownership preserved-through-migration rather than styling taste. The rest of the migration (banner primitives composed from Button/ScrollArea, ScrollArea replacing the hand-rolled overflow-y-auto task list, [data-composer-banner-surface="attached"] replacing the per-class :has() selectors, .chat-composer-shoulder-tab retained as the marker ChatView still keys group-has-[...] off) looks consistent.
Posted via Macroscope — UI Consistency
| <ComposerBanner.ToggleIcon expanded={!isCollapsed} /> | ||
| </ComposerBanner.Actions> | ||
| </CollapsibleTrigger> | ||
| <CollapsiblePanel> |
There was a problem hiding this comment.
CollapsiblePanel clips permanently (overflow-hidden in the primitive), and the padding that used to keep content off that clip is gone: the old panel carried px-3 sm:px-4 plus pt-2 pb-0.5, while ComposerBanner.Body only pads the inline start (ps-…). The option buttons are w-full with focus-visible:ring-1, which paints outside the border box, so the ring is now shaved on the end edge of every option and on the bottom edge of the last one — exactly the failure the removed comment warned about.
Smallest fix is to give the clipping element a little end/bottom room:
| <CollapsiblePanel> | |
| <CollapsiblePanel className="pe-1 pb-1"> |
Posted via Macroscope — UI Consistency
| <div | ||
| data-slot="composer-banner-attachment" | ||
| className={cn( | ||
| "mx-auto -mb-[calc(1rem+1px)] w-[calc(100%-2.75rem)] max-w-[45.25rem]", |
There was a problem hiding this comment.
This hardcodes the attachment geometry (2.75rem = 2 × 1.375rem inset, 45.25rem = 48rem − inset × 2) while the PR deletes the --chat-composer-drawer-inset: 1.375rem declaration from index.css. That token still has an imperative consumer: ChatComposer.tsx:200 reads it with getComputedStyle(...).getPropertyValue("--chat-composer-drawer-inset") to position the command-menu layer, and now always lands on its || 1.375 fallback. Nothing breaks today only because the literal here and the fallback there happen to agree — the two can silently drift the next time this width changes.
Suggest picking one owner: either keep the custom property (declared on [data-chat-composer-form="true"]) and consume it here (w-[calc(100%-2*var(--chat-composer-drawer-inset))], max-w-[calc(48rem-2*var(--chat-composer-drawer-inset))]), or drop the now-dead getComputedStyle read in ChatComposer and export the inset as a shared constant.
Posted via Macroscope — UI Consistency
|
Composer screenshots from Working stays attached to the composer. Update notices, including failures and retry progress, stay in the stack behind it. Revealing a failed update keeps Working attached, with both Retry and dismiss available: Checked task expansion, notice hit areas, retry, and dismissal in the web client. Scoped typecheck, lint, and formatting passed. |
## What's Changed * Remove Messages Glass Lab experiment by @juliusmarminge in pingdotgg/t3code#8599 * Require human review for pull requests changing product defaults by @juliusmarminge in pingdotgg/t3code#8603 * fix(codex): avoid quadratic app-server input buffering by @juliusmarminge in pingdotgg/t3code#8605 * fix(mobile): stabilize iOS header item transitions by @juliusmarminge in pingdotgg/t3code#8607 * chore(mobile): upgrade to Expo SDK 57 by @juliusmarminge in pingdotgg/t3code#8609 * fix(mobile): harden native header toolbar items by @juliusmarminge in pingdotgg/t3code#8611 * fix(server): stop querying Claude context usage after turns by @t3dotgg in pingdotgg/t3code#8610 * chore: vouch ryanrhughes by @t3dotgg in pingdotgg/t3code#8613 * feat(web): attach PDFs, ZIPs, and other files to a turn by @t3dotgg in pingdotgg/t3code#8236 * feat(web): keybinding settings as settings rows by @StiensWout in pingdotgg/t3code#8532 * feat: let an environment publish themes as a file by @ryanrhughes in pingdotgg/t3code#8569 * fix(web): clean up provider settings list and editor by @StiensWout in pingdotgg/t3code#8504 * fix(web): keep project picker popup inside the sidebar by @SunkenInTime in pingdotgg/t3code#8627 * fix(mobile): prevent header overflow and back-button artifacts by @juliusmarminge in pingdotgg/t3code#8624 * fix(server): retry automatic thread title generation by @Bil0000 in pingdotgg/t3code#8087 * fix(client-runtime): refresh edited pull request comments by @Bil0000 in pingdotgg/t3code#8094 * fix(web): four composer spacing defects by @Bil0000 in pingdotgg/t3code#8090 * perf(desktop): skip duplicate browser updates by @Bil0000 in pingdotgg/t3code#8018 * fix(web): render nested markdown images correctly by @flamboh in pingdotgg/t3code#8501 * fix(web): unify activity logs and composer banners by @juliusmarminge in pingdotgg/t3code#8693 * fix(mobile): reduce dev-client reload and Metro startup cost by @juliusmarminge in pingdotgg/t3code#8694 * revert(web): restore previous composer banners by @t3dotgg in pingdotgg/t3code#8733 * test(web): remove tests for unreachable helpers by @t3-code[bot] in pingdotgg/t3code#8738 * feat(mobile): update tool summaries and chat transitions by @juliusmarminge in pingdotgg/t3code#8793 * feat(web): play video attachments in chat by @Bil0000 in pingdotgg/t3code#8688 * fix(web,mobile): snooze menu no longer offers the same wake time twice by @vitalyiegorov in pingdotgg/t3code#8741 * fix(grok): allow model changes in existing threads by @ahmed-besic in pingdotgg/t3code#8392 * feat(mobile): pick, share, and receive files in threads by @t3dotgg in pingdotgg/t3code#8237 * fix(web): reduce title bar scroll fade height by @maria-rcks in pingdotgg/t3code#8799 * fix(windows): strip quotes from repaired PATH by @UtkarshUsername in pingdotgg/t3code#8746 * fix(web): open agent images in expanded preview by @maria-rcks in pingdotgg/t3code#8807 * fix(git): follow repository instructions in generated source control text by @maria-rcks in pingdotgg/t3code#8804 * fix(server): stop overpricing cached Claude tokens by @SunkenInTime in pingdotgg/t3code#8806 * fix(web): keep image preview above sidebar control by @maria-rcks in pingdotgg/t3code#8811 * fix(web): keep right panel synced with agent edits by @maria-rcks in pingdotgg/t3code#8803 * fix(web,mobile): render Codex citations and artifact templates by @Yash-Singh1 in pingdotgg/t3code#8584 * chore: add Windows setup script to t3.json by @UtkarshUsername in pingdotgg/t3code#8814 * fix(web): fold interim turn responses by @maria-rcks in pingdotgg/t3code#8828 * fix(web): use circle alert for failed tool calls by @maria-rcks in pingdotgg/t3code#8840 * feat(mobile): add offline iPhone voice input by @t3dotgg in pingdotgg/t3code#8614 * fix(web): prevent pull request metadata overlap by @MatthewFeroz in pingdotgg/t3code#8790 ## New Contributors * @ryanrhughes made their first contribution in pingdotgg/t3code#8569 * @ahmed-besic made their first contribution in pingdotgg/t3code#8392 * @MatthewFeroz made their first contribution in pingdotgg/t3code#8790 **Full Changelog**: pingdotgg/t3code@v0.0.36...v0.0.37 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.37









Note
Medium Risk
Large UI refactor across composer, timeline, and system banners with prop renames (
externalDrawerAttached→bannerItems, etc.) that can affect stacking order, scroll padding, and in-flight turn visibility.Overview
Unifies chat composer notices and live status around new
ComposerBannerandComposerSurfaceprimitives, instead of scattered glass-shell classes andAlert-based stacks.Banners, stash/tasks shoulders, pending-approval drawers, and command menus now share the same attachment/dock layout.
ComposerBannerStacksorts items bypriority(activity,urgent,notice) with keyboard-friendly peek/expand, andChatComposerowns the stack (viabannerItems) plus a dedicated activity slot for thread sync and “Working…” timers—replacing the separateThreadSyncStatusPilland timelineworkingrows. Task progress is derived from the active turn’s plan steps (not sidebar shell state) and can embed that activity row; per-turn task dismiss is removed.ChatViewwraps the composer inComposerSurface.Shell/Host/Main, dropsshoulderTabReservescroll adjustment, and tightens server-update banners (ComposerServerUpdateStatus, failed-update dismiss).BranchToolbarusesComposerSurface.ContextStrip. Several markup-focused component tests were removed or narrowed as layouts moved to the shared primitives.Reviewed by Cursor Bugbot for commit 078c289. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Unify activity logs and composer banners in chat composer
ComposerBannerprimitives and refactors the chat composer UI (tasks, stash, command menu, server updates) to use themworkingrows and theMAX_VISIBLE_WORK_LOG_ENTRIEStruncation fromMessagesTimeline; work log entries are now grouped and summarized directly, including non-toolupdateentriesturn.plan.updatedactivities from the derived work log in session-logic.tsdismissServerUpdateFailureandisServerUpdateFailureDismissedto versionSkew.ts to track dismissed failed server updates in memoryChatComposerPropsdropsexternalDrawerAttachedand requiresbannerItems;MessagesTimelineRowremoves theworkingvariant;shoulderTabReserveis deleted from ChatView.logic.ts; severalchat-composer-*CSS classes are removed from index.cssMacroscope summarized 078c289.