Skip to content

fix(web): unify activity logs and composer banners - #8693

Merged
juliusmarminge merged 8 commits into
mainfrom
fix/composer-activity-log
Aug 29, 2026
Merged

fix(web): unify activity logs and composer banners#8693
juliusmarminge merged 8 commits into
mainfrom
fix/composer-activity-log

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Aug 29, 2026

Copy link
Copy Markdown
Member

Note

Medium Risk
Large UI refactor across composer, timeline, and system banners with prop renames (externalDrawerAttachedbannerItems, etc.) that can affect stacking order, scroll padding, and in-flight turn visibility.

Overview
Unifies chat composer notices and live status around new ComposerBanner and ComposerSurface primitives, instead of scattered glass-shell classes and Alert-based stacks.

Banners, stash/tasks shoulders, pending-approval drawers, and command menus now share the same attachment/dock layout. ComposerBannerStack sorts items by priority (activity, urgent, notice) with keyboard-friendly peek/expand, and ChatComposer owns the stack (via bannerItems) plus a dedicated activity slot for thread sync and “Working…” timers—replacing the separate ThreadSyncStatusPill and timeline working rows. 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.

ChatView wraps the composer in ComposerSurface.Shell/Host/Main, drops shoulderTabReserve scroll adjustment, and tightens server-update banners (ComposerServerUpdateStatus, failed-update dismiss). BranchToolbar uses ComposerSurface.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

  • Introduces ComposerBanner primitives and refactors the chat composer UI (tasks, stash, command menu, server updates) to use them
  • Removes working rows and the MAX_VISIBLE_WORK_LOG_ENTRIES truncation from MessagesTimeline; work log entries are now grouped and summarized directly, including non-tool update entries
  • Excludes turn.plan.updated activities from the derived work log in session-logic.ts
  • Adds dismissServerUpdateFailure and isServerUpdateFailureDismissed to versionSkew.ts to track dismissed failed server updates in memory
  • Risk: ChatComposerProps drops externalDrawerAttached and requires bannerItems; MessagesTimelineRow removes the working variant; shoulderTabReserve is deleted from ChatView.logic.ts; several chat-composer-* CSS classes are removed from index.css

Macroscope summarized 078c289.

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.
@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b44ec0da-f7ba-4164-b9db-44ffa1f3c6e9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 29, 2026
@github-actions

github-actions Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.3 KiB 13.3 KiB −42 B (−0.3%) 15.1 KiB
Codex Thread snapshot wire 6.9 KiB 6.9 KiB −8 B (−0.1%) 7.3 KiB
Codex Live turn WebSocket wire 6.4 KiB 6.4 KiB −34 B (−0.5%) 7.8 KiB
Codex Live turn WebSocket decoded 55.6 KiB 55.6 KiB −44 B (−0.1%) 66.4 KiB
Codex Live turn messages 11 10 −1 (−9.1%) 21
Claude Total thread wire 13.3 KiB 13.3 KiB +4 B (+0.0%) 15.1 KiB
Claude Thread snapshot wire 6.9 KiB 6.9 KiB −8 B (−0.1%) 7.3 KiB
Claude Live turn WebSocket wire 6.4 KiB 6.5 KiB +12 B (+0.2%) 7.8 KiB
Claude Live turn WebSocket decoded 56.4 KiB 56.4 KiB 0 B (0.0%) 66.4 KiB
Claude Live turn messages 11 11 0 (0.0%) 21

Baseline: c0e09f3 · PR result: 078c289 · Source CI: success

Scenario and decoded snapshot size

10 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.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp macroscopeapp Bot 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.

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">

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.

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.

Suggested change
<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"

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.

--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.

Suggested change
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"

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.

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.

Suggested change
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);

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.

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

@macroscopeapp macroscopeapp Bot 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.

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 permanently overflow-hidden CollapsiblePanel, shaving their focus ring on the trailing side (the removed px-3 sm:px-4 comment warned about exactly this).
  • ComposerTasksBadge.tsx / ComposerStashMenu.tsx: the task and stash lists lost the explicit role="list" / role="listitem" they used to carry, while the new ul/li are rendered with display: grid.

Posted via Macroscope — UI Consistency

{expanded ? (
<ComposerBanner.Scroll data-composer-tasks-scroll="true">
<ComposerBanner.Children
render={<ul />}

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.

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:

Suggested change
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>

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.

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:

Suggested change
<CollapsiblePanel>
<CollapsiblePanel className="pe-1">

Posted via Macroscope — UI Consistency

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit 74d4ba6. Configure here.

Comment thread apps/web/src/components/chat/ComposerPendingUserInputPanel.tsx
@macroscopeapp

macroscopeapp Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: 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.

@macroscopeapp macroscopeapp Bot 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.

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>

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.

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:

Suggested change
<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]",

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.

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

@juliusmarminge

Copy link
Copy Markdown
Member Author

Composer screenshots from 078c28963bf, using synthetic review fixtures.

Working stays attached to the composer. Update notices, including failures and retry progress, stay in the stack behind it.

Working attached with the update notice peeking behind it

Revealing a failed update keeps Working attached, with both Retry and dismiss available:

Failed update revealed above the attached Working row

Expanded tasks and revealed update notice

Expanded tasks and revealed update notice

Syncing hides the working timer and cached tasks

Syncing hides the working timer and cached tasks

Long task list with scroll fade

Long task list with scroll fade

Stash uses the shared banner layout

Stash uses the shared banner layout

Dark mode

Dark mode

Narrow viewport

Narrow viewport

Checked task expansion, notice hit areas, retry, and dismissal in the web client. Scoped typecheck, lint, and formatting passed.

@juliusmarminge
juliusmarminge merged commit 3d32797 into main Aug 29, 2026
26 of 27 checks passed
@juliusmarminge
juliusmarminge deleted the fix/composer-activity-log branch August 29, 2026 23:38
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Aug 31, 2026
## 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant