Skip to content

Fix ChatView header overflow for long thread titles - #60

Merged
juliusmarminge merged 2 commits into
mainfrom
codething/d847b414
Feb 18, 2026
Merged

juliusmarminge merged 2 commits into
mainfrom
codething/d847b414

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Feb 16, 2026 •

Copy link
Copy Markdown
Member

Summary

  • add min-w-0 to ChatView container wrappers so header content can shrink within flex layouts
  • update header title container to flex-1 min-w-0 and apply truncate to the thread title
  • add a title tooltip on the truncated thread name to preserve full-title visibility
  • mark the header action group as shrink-0 so controls remain stable when titles are long

Testing

  • Not run (no test output provided)
  • Visual check: long thread titles should truncate with ellipsis instead of overflowing header controls

Open with Devin

Summary by CodeRabbit

  • New Features

    • Enforced a 4-terminal-per-thread limit; creating or splitting terminals is blocked at the cap and action labels reflect the max.
    • Terminal action buttons are disabled and visually dimmed when the limit is reached.
  • Improvements

    • Chat header shows long titles with truncation and tooltip; layout tweaks prevent overflow and unwanted shrinking.
  • Tests

    • Added tests verifying the terminal cap and related behaviors.

Note

Low Risk
Mostly UI/layout tweaks plus a straightforward terminal-count cap with added reducer guards and tests; limited blast radius to thread terminal management and display.

Overview
Fixes chat header layout issues with long thread titles by adding min-w-0/truncate and a hover title tooltip, and by marking the actions area as shrink-0 so controls don’t get pushed off-screen.

Introduces a shared MAX_THREAD_TERMINAL_COUNT (set to 4) and enforces it end-to-end: UI actions for split/new terminals are disabled with updated tooltips when at the cap, the reducer ignores attempts to add beyond the limit (including on hydration/normalization), and new tests cover both split and new terminal capping behavior.

Written by Cursor Bugbot for commit dcc6d9d. This will update automatically on new commits. Configure here.

- add `min-w-0` to ChatView container wrappers to allow proper flex shrinking
- make thread title truncatable with `truncate` and `title` tooltip
- keep action controls fixed-width with `shrink-0` to preserve header layout
@coderabbitai

coderabbitai Bot commented Feb 16, 2026 •

Copy link
Copy Markdown

Walkthrough

Adds a MAX_THREAD_TERMINAL_COUNT limit (value 4) and enforces it across UI and store: ChatView and ThreadTerminalDrawer now guard split/new terminal actions and adjust layout/labels when the cap is reached; store normalization and reducers prevent creating terminals beyond the cap; tests added to validate behavior.

Changes

Cohort / File(s) Summary
ChatView (layout + terminal gating)
apps/web/src/components/ChatView.tsx
Added MAX_THREAD_TERMINAL_COUNT import and ChatImageAttachment type. Added hasReachedTerminalLimit logic to short-circuit splitTerminal and createNewTerminal. Added min-w-0 to empty-state and main content containers; updated ChatHeader title rendering with truncation and title attribute and adjusted flex/shrink classes.
ThreadTerminalDrawer (UI + guards)
apps/web/src/components/ThreadTerminalDrawer.tsx
Introduced MAX_THREAD_TERMINAL_COUNT and hasReachedTerminalLimit. Wrapped split/new actions with guarded handlers that no-op when limit reached, update action labels to reflect limit, disable/dim buttons and suppress hover when capped, and adjust layout/grid overflow classes for terminal panels.
Store (state enforcement + normalization)
apps/web/src/store.ts
Added/used MAX_THREAD_TERMINAL_COUNT. Normalization now deduplicates and slices terminal lists to the max, ensures valid activeThreadId fallback, and reducers for SPLIT_THREAD_TERMINAL/NEW_THREAD_TERMINAL skip creating new terminals when the cap would be exceeded.
Tests (behavior validation)
apps/web/src/store.test.ts
Added tests asserting a maximum of four terminals per thread when splitting/creating terminals; imports MAX_THREAD_TERMINAL_COUNT and verifies terminal count, ordering, and active terminal behavior near the cap.
Types (public constant)
apps/web/src/types.ts
Added exported MAX_THREAD_TERMINAL_COUNT = 4.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant UI as ThreadTerminalDrawer / ChatView
    participant Store as Store (reducers)

    User->>UI: Click "Split" or "New Terminal"
    UI->>UI: check hasReachedTerminalLimit (reads terminals count)
    alt limit reached
        UI-->>User: no-op, show disabled state / label indicating max
    else below limit
        UI->>Store: dispatch SPLIT_THREAD_TERMINAL / NEW_THREAD_TERMINAL
        Store->>Store: normalize terminals, enforce MAX_THREAD_TERMINAL_COUNT
        alt store accepted
            Store-->>UI: updated state with new terminal
            UI-->>User: render new terminal
        else rejected (would exceed)
            Store-->>UI: state unchanged
            UI-->>User: maintain current UI (action prevented)
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Fix ChatView header overflow for long thread titles' accurately describes the primary CSS/layout changes to prevent overflow in ChatView headers with long titles. However, the changeset also introduces terminal count limiting (4 terminal max per thread) across multiple files (store.ts, store.test.ts, ThreadTerminalDrawer.tsx), which represents substantial functionality changes not mentioned in the title. Update the title to reflect both major changes, such as: 'Add terminal limit and fix ChatView header overflow' or split into separate PRs if these are logically distinct concerns.
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codething/d847b414

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

@macroscopeapp

macroscopeapp Bot commented Feb 16, 2026 •

Copy link
Copy Markdown
Contributor

Prevent ChatView header overflow for long thread titles and cap thread terminals at 4 across UI actions and store logic

Introduce MAX_THREAD_TERMINAL_COUNT = 4 and enforce it in UI actions and reducers; truncate the Chat header title and apply min-w-0/overflow fixes; normalize persisted terminal IDs and validate activeThreadId.

📍Where to Start

Start with the terminal cap logic in the reducers in store.ts, then review header truncation and overflow fixes in ChatView.tsx.


Macroscope summarized dcc6d9d.

@greptile-apps

greptile-apps Bot commented Feb 16, 2026

Copy link
Copy Markdown

Greptile Summary

Fixes header overflow in ChatView when thread titles are long. Adds min-w-0 to the ChatView flex containers so they can shrink within the parent Layout flex row, applies truncate to the h2 thread title (with a native title tooltip for full-text visibility), and marks the header action buttons as shrink-0 so controls remain stable regardless of title length.

  • Adds min-w-0 to both ChatView wrapper divs (empty state and active thread) to allow proper flex shrinking
  • Updates ChatHeader left container to flex-1 min-w-0 so the title area claims remaining space and can truncate
  • Adds truncate and title attribute to the thread title h2
  • Marks the right-side action group as shrink-0 to prevent button controls from being compressed

Confidence Score: 5/5

  • This PR is safe to merge — it applies minimal, well-understood CSS flex overflow fixes with no behavioral or logic changes.
  • The changes are purely cosmetic CSS class additions (min-w-0, truncate, shrink-0, flex-1) and an HTML title attribute. The flex overflow pattern used here is standard and well-established. No JavaScript logic, state, or component API changes are involved. The Badge component already has shrink-0 in its base styles, so it integrates correctly with the new layout.
  • No files require special attention.

Important Files Changed

Filename Overview
apps/web/src/components/ChatView.tsx Adds min-w-0 to outer flex containers, applies truncate with title tooltip to thread title, and marks action buttons shrink-0 to prevent header overflow with long thread names. Standard CSS flex overflow fix with no behavioral regressions.

Flowchart

flowchart TD
    A["Layout (flex h-screen overflow-hidden)"] --> B["Sidebar"]
    A --> C["ChatView (flex-1 min-w-0)"]
    A --> D["DiffPanel (conditional)"]
    C --> E["header (flex justify-between)"]
    C --> F["Messages area"]
    E --> G["Left: title container (flex-1 min-w-0)"]
    E --> H["Right: actions (shrink-0)"]
    G --> I["h2 thread title (truncate + title tooltip)"]
    G --> J["Badge project name (shrink-0)"]
    H --> K["OpenInPicker / GitActions / Diff button"]
Loading

Last reviewed commit: 0a4c070

- enforce max 4 terminals per thread in reducer and terminal normalization
- block split/new terminal actions in chat and drawer when limit is reached
- add reducer tests for split/new terminal cap behavior

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

🧹 Nitpick comments (1)
apps/web/src/components/ThreadTerminalDrawer.tsx (1)

718-740: Consider adding aria-disabled for better accessibility.

The buttons are visually styled as disabled but don't communicate this state to assistive technologies. While the tooltip message helps, adding aria-disabled="true" when hasReachedTerminalLimit would improve screen reader accessibility.

♿ Proposed accessibility improvement
 <TerminalActionButton
   className={`p-1 text-foreground/90 transition-colors ${
     hasReachedTerminalLimit
       ? "cursor-not-allowed opacity-45 hover:bg-transparent"
       : "hover:bg-accent"
   }`}
   onClick={onSplitTerminalAction}
   label={splitTerminalActionLabel}
+  aria-disabled={hasReachedTerminalLimit}
 >

Note: This would require updating the TerminalActionButtonProps interface to accept an optional aria-disabled prop and pass it through to the button element.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/ThreadTerminalDrawer.tsx` around lines 718 - 740, The
TerminalActionButton instances should convey the disabled state to assistive
tech: update the TerminalActionButton component and its
TerminalActionButtonProps to accept an optional aria-disabled boolean prop, pass
that prop through to the underlying button element, and set
aria-disabled={hasReachedTerminalLimit} on both usages (the
SquareSplitHorizontal and Plus buttons) when the visual disabled styling is
applied; ensure the existing onClick still respects the disabled state (no-op or
prevented) to match aria-disabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/web/src/components/ThreadTerminalDrawer.tsx`:
- Around line 718-740: The TerminalActionButton instances should convey the
disabled state to assistive tech: update the TerminalActionButton component and
its TerminalActionButtonProps to accept an optional aria-disabled boolean prop,
pass that prop through to the underlying button element, and set
aria-disabled={hasReachedTerminalLimit} on both usages (the
SquareSplitHorizontal and Plus buttons) when the visual disabled styling is
applied; ensure the existing onClick still respects the disabled state (no-op or
prevented) to match aria-disabled.

@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 and found 1 potential issue.

Bugbot Autofix is ON. A Cloud Agent has been kicked off to fix the reported issue.

Comment thread apps/web/src/components/ThreadTerminalDrawer.tsx
@cursor

cursor Bot commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Bugbot Autofix prepared fixes for 1 of the 1 bugs found in the latest run.

  • ✅ Fixed: Split terminal minimum width removed, prevents scrolling
    • Restored minmax(260px, 1fr) and overflow-x-auto on the split terminal grid while keeping the min-w-0 class that prevents the grid from expanding the parent flex container, preserving the header overflow fix.

Create PR

Or push these changes by commenting:

@cursor push cfabf9bd03
Preview (cfabf9bd03)
diff --git a/apps/web/src/components/ThreadTerminalDrawer.tsx b/apps/web/src/components/ThreadTerminalDrawer.tsx
--- a/apps/web/src/components/ThreadTerminalDrawer.tsx
+++ b/apps/web/src/components/ThreadTerminalDrawer.tsx
@@ -755,9 +755,9 @@
           <div className="min-w-0 flex-1">
             {isSplitView ? (
               <div
-                className="grid h-full w-full min-w-0 gap-0 overflow-hidden"
+                className="grid h-full w-full min-w-0 gap-0 overflow-x-auto"
                 style={{
-                  gridTemplateColumns: `repeat(${visibleTerminalIds.length}, minmax(0, 1fr))`,
+                  gridTemplateColumns: `repeat(${visibleTerminalIds.length}, minmax(260px, 1fr))`,
                 }}
               >
                 {visibleTerminalIds.map((terminalId) => (

@juliusmarminge
juliusmarminge merged commit 376efdd into main Feb 18, 2026
4 checks passed
aorwall added a commit to aorwall/t3code that referenced this pull request Aug 6, 2026
…serves (pingdotgg#60)

Two gaps in the framed preview, both about a server that is still starting.

The picker collapsed every non-started status into one grey dot that differed
only by its aria-label, so `installing`, `starting`, `failed` and `stopped`
looked identical. The states that resolve on their own now spin, `failed` is
marked as such, and each carries its word — the row was otherwise readable by
colour alone.

The second is the reason the panel looked broken. A frame pointed at a server
that has not started loads the proxy's error page; the backend hands a starting
server the ingress URL its port will have, so the picker offers it and the tab
takes it. `PreviewServerNotStarted` then covers the frame, and when the server
reaches `started` that overlay clears — over the dead page, which nothing
replaces. Refresh was the only way out, and before this the 12-second "Still
blank?" hint was the only thing that suggested it.

Moatless's own panel cannot reach this state because it does not mount the
iframe until the server reports `started`, so the element's first load is always
of a page being served. A frame here cannot be gated that way — it is mounted at
the app root to survive the panel — so it is replaced on the transition instead,
through the existing reload-nonce that re-keys the element.

Which tabs are holding a page loaded too early is module state, not panel state:
the preview panel unmounts whenever the right panel switches to Files or a
terminal, which is exactly what someone does while waiting for a slow server.

The decision itself is a pure function, tested directly; the hook around it is
one additive line in upstream's `PreviewView.tsx`. Verified against
`upstream/main` that the four files this touches under `components/preview/` are
fork-only, and recorded them in the merge inventory.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
i2cjak referenced this pull request in i2cjak/Backplane Sep 29, 2026
type_bench: a real log and thread, any window size, caret blinks, repeated passes
YuryYudin added a commit to YuryYudin/t3code that referenced this pull request Oct 10, 2026
Nightly integration builds pingdotgg#60 and pingdotgg#61 stopped at the quality gate after
merging upstream main. The automatic repair resolved the merge, but five
fork-owned tests still referred to code that upstream refactored:

- serverSettings: the collections persistence test used the removed
  makeServerSettingsLayer helper; it now uses layerServerSettings.
- HomeHeader collections: upstream's iOS header now reads navigation and
  the adaptive layout, which loaded react-native's Flow entry point in
  Vitest; both are mocked the way HomeRouteScreen's test does.
- connection registry: the harness authenticated every route after the
  merge, so the Tailscale repair test hung on the non-bearer target; the
  bearer-only guard is restored.
- MaintenanceDispatch: ProviderAdapter moved to
  @t3tools/provider-core/server/ProviderAdapter.
- DesktopAppIdentity: upstream's new tests assert its "Alpha" stage, but
  fork builds call the stable stage "Latest" and show the bare product
  name, so the expectations follow the fork's shipped branding.

Implemented by Claude Sonnet 5 subagents and reviewed by Claude Opus 5.5
in Claude Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TomCohenDev pushed a commit to TomCohenDev/t3code that referenced this pull request Oct 18, 2026
…ptions

feat(fork): edit the snooze menu quick options
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