Skip to content

🤖 fix: fade sideways-scrolling rows, full skill descriptions, keep pop-out terminals out of the sidebar - #5732

Merged
ThomasK33 merged 4 commits into
mainfrom
fix/scroll-row-fade-skill-descriptions
Oct 6, 2026
Merged

ThomasK33 merged 4 commits into
mainfrom
fix/scroll-row-fade-skill-descriptions

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Summary

Three small layout and terminal fixes from the bug bash:

  • Rows that scroll sideways with a hidden scrollbar (workspace footer, Timeline filter chips) now fade the edge where more items sit past it.
  • The Skills popover shows each skill's full description instead of one line.
  • A terminal open in a pop-out window no longer comes back as a (often hidden) right-sidebar tab when the main window reloads. In the desktop app, closing the pop-out window ends its session.

Fixes #5696
Fixes #5697
Fixes #5673

Implementation

#5696 One shared CSS class, scroll-fade-x, in scrollbar-none.css (shared with the VS Code webview, because both rows are webview-importable). It is scroll-driven CSS (animation-timeline: scroll(self inline) animating two registered @property lengths into a mask-image), so there is no JS and no per-render work. A row that fits has an inactive scroll timeline and shows no fade. Browsers without scroll timelines keep today's plain row.

#5697 The description drops line-clamp-1 and wraps (break-words). The list already scrolls inside max-h-[min(400px,60vh)]. I chose full text over click-to-expand because expanding would be a new operation that needs its own keyboard shortcut.

#5673 (coordinator-approved design, no persisted state):

  1. Pop-out terminal windows mount TerminalRouterProvider popout, so their terminal.attach calls send popout: true (new optional input field, no new subscription).
  2. While such an attach stream is open, TerminalService counts the session as shown in a pop-out, and terminal.listSessions skips it. So the right sidebar's reload sync (and layout presets) do not adopt it.
  3. The count drops when the stream ends: the pop-out closed, crashed, reloaded or lost its connection. A backend restart starts with no counts.
  4. Desktop: TerminalWindowManager reports a closed pop-out window, and TerminalService closes that session. This matches closing a sidebar terminal tab, which also does not ask first. Reloading or crashing a pop-out does not close its window, so the session survives those.
  5. Browser mode (documented decision): a pop-out page cannot tell its window closing from its own reload, so closing a browser pop-out does not end the session. Killing it would lose the shell on every pop-out reload. After the pop-out closes, the session returns as a sidebar tab on the next main-window load, which is today's recovery path.

Validation

Test-first for #5673. Before the fix:

TypeError: service.markPopoutAttached is not a function
(fail) TerminalService > pop-out attachments (#5673) > a session with a live pop-out is not listed, so the sidebar does not adopt it
(fail) TerminalService > pop-out attachments (#5673) > the session stays hidden until every pop-out attach for it has ended
(fail) TerminalService > pop-out attachments (#5673) > closing the desktop pop-out window ends its session

routerSubscriptions.test.ts adds the stream-level test (reload-adoption and crash path): a pop-out attach hides the session while it is live, and aborting it lists the session again. If attachTerminal ignores the flag, the test fails. vscode/src/webview/webviewCss.test.ts passes (it first caught the class living only in desktop CSS, so the class moved to the shared file).

#5696 and #5697 are CSS-only. Asserting class names would be a tautological test, so the evidence is measured in the browser (agent-browser against tests/bugbash/startApp.ts servers built from main and from this branch):

Check main this branch
Footer row at 375px (scrollWidth 430 > clientWidth 375) cut at the edge, no hint right edge fades; after scrolling to the end the left edge fades
Timeline chip row in the default sidebar (438 > 373) cut chip, no hint edge fades
Skills popover: first 10 description spans clipped 9 of 10 0 of 10 (desktop and 375px)
Main-window reload with a browser pop-out terminal open session added as a sidebar Terminal tab no tab added
Main-window reload after that browser pop-out is closed tab tab (session comes back, as designed)

Footer at 375px: main (top), branch at the start (middle), branch scrolled to the end (bottom):

Footer row at 375px

Timeline chips (row narrowed to 240px, as in a narrow sidebar): main (top), branch (bottom):

Timeline chip row

Skills popover on main (desktop) and on this branch (375px):

Skills popover on main

Skills popover on this branch at 375px

Risks

Low. The fade only paints a mask on two rows and needs scroll-timeline support (Chromium, so Electron and the VS Code webview). Long skill descriptions make the popover list taller, and it scrolls. listSessions now hides sessions that a pop-out shows, so the layout-preset terminal mapping also skips them, which matches the intent. Closing a desktop pop-out now kills its shell. Before, the shell kept running unseen until the sidebar adopted it.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $3.19

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-06T12:50:02.413430Z 5acf2bb New commits
🔒 Security Review ✅ Completed 2026-10-06T12:50:47.138247Z 5acf2bb New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fceed5de26

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/desktop/terminalWindowManager.ts Outdated
@ThomasK33
ThomasK33 force-pushed the fix/scroll-row-fade-skill-descriptions branch from fceed5d to 5acf2bb Compare October 6, 2026 12:46
@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 6, 2026
Merged via the queue into main with commit c225a74 Oct 6, 2026
32 of 33 checks passed
@ThomasK33
ThomasK33 deleted the fix/scroll-row-fade-skill-descriptions branch October 6, 2026 13:27
yermakoffivan pushed a commit to yermakoffivan/mux that referenced this pull request Oct 6, 2026
## Summary

In the desktop app, when the shell in one pop-out terminal window exits,
only that window closes now. Other pop-out terminal windows of the same
workspace stay open.

Fixes coder#5739

## Background

`terminal-window.tsx` called `terminal.closeWindow({ workspaceId })`
when its shell exited, and
`TerminalWindowManager.closeTerminalWindow(workspaceId)` closed every
pop-out of that workspace. Since coder#5732, those windows keep their
sessions (app-closed windows are not user closes), but they were still
hidden, and their shells came back as sidebar tabs on the next load.

## Implementation

1. `terminal.closeWindow` takes an optional `sessionId` (`.nullish()`).
The pop-out window sends its own session when its shell exits.
2. A new Electron-free `TerminalWindowRegistry`
(`src/desktop/terminalWindowRegistry.ts`) records which session each
pop-out window shows, and selects the windows to close: only the one
showing `sessionId`, or all of them when the field is absent (unchanged
for other callers).
3. `TerminalWindowManager` uses the registry instead of its own
`Map<workspaceId, Set<BrowserWindow>>`. I kept the registry free of
Electron imports because `terminalWindowManager.ts` cannot load under
bun (`electron` has no `BrowserWindow` export there), so the close rule
needed a testable home.
4. It also merges a duplicate doc comment on
`TerminalService.getWorkspaceSessionIds` left by coder#5732 (flagged by that
PR's final check).

## Validation

`src/desktop/terminalWindowRegistry.test.ts` "when one of two pop-outs
exits, only its window is closed and the other stays open": two pop-outs
are open in one workspace and one exits. The test asserts that only that
window is selected, and that the other stays registered. With the old
"close every window of the workspace" rule restored inside the registry,
the test fails:

```
+   "window-b",
- Expected  - 0
+ Received  + 1
(fail) TerminalWindowRegistry (coder#5739) > when one of two pop-outs exits, only its window is closed and the other stays open
```

No screenshots: the behavior exists only in the Electron app (in browser
mode `closeWindow` is a no-op on the server, and each browser pop-out is
its own tab). I did not run Electron for this change. Its window wiring
is the 1:1 replacement of the old Map/Set shown in the diff.

## Risks

Low. Callers that omit `sessionId` keep the old close-all behavior. A
pop-out opened without a session (none exist today, because
`openTerminalPopout` always passes one) is closed only by a close-all.

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking:
`high` • Cost: `$16.86`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant