Repository navigation
Fix ChatView header overflow for long thread titles - #60
Conversation
- 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
WalkthroughAdds 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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
Prevent ChatView header overflow for long thread titles and cap thread terminals at 4 across UI actions and store logicIntroduce 📍Where to StartStart 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 SummaryFixes header overflow in
Confidence Score: 5/5
Important Files Changed
Flowchartflowchart 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"]
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
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/web/src/components/ThreadTerminalDrawer.tsx (1)
718-740: Consider addingaria-disabledfor 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"whenhasReachedTerminalLimitwould 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
TerminalActionButtonPropsinterface to accept an optionalaria-disabledprop 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.
|
Bugbot Autofix prepared fixes for 1 of the 1 bugs found in the latest run.
Or push these changes by commenting: 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) => ( |
…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>
type_bench: a real log and thread, any window size, caret blinks, repeated passes
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>
…ptions feat(fork): edit the snooze menu quick options

Summary
min-w-0to ChatView container wrappers so header content can shrink within flex layoutsflex-1 min-w-0and applytruncateto the thread titletitletooltip on the truncated thread name to preserve full-title visibilityshrink-0so controls remain stable when titles are longTesting
Summary by CodeRabbit
New Features
Improvements
Tests
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/truncateand a hovertitletooltip, and by marking the actions area asshrink-0so 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.