Monitoring sidebar toggle, Prompts-style Tools results, and icon-button UI polish (#1661) (#1662)

* feat(web): single header MonitoringToggle + Prompts-style Tools results (#1661)

Consolidate the monitoring column's open/close affordances into one header
toggle, and align the Tools/Prompts result panes and the sidebar log layout.

- Add a single `MonitoringToggle` in the header, to the right of the theme
  icon. It opens/closes the monitoring column and only shows when a server is
  connected OR a connect attempt failed (wide viewport + a monitor tab
  available) — the same availability rule the column uses.
- Remove the scattered pin/close icons: delete `PinColumnButton`; drop `onPin`
  from the Logs/Protocol/Network/Console screens and their stream panels; drop
  `onOpenMonitor` from the server list; remove the close button from
  `MonitoringControls`/`MonitoringScreen`.
- Tools screen: remove the "Results will appear here" placeholder pane. Results
  now replace the input form in a single content pane (the Prompts pattern),
  with a top-left X (ToolResultPanel) that dismisses them back to the form;
  form values are preserved for a re-run.
- Prompts screen: the argument form fills the content pane width (drop the 40%
  cap), matching the Tools input.
- LogEntry: add a `compact` two-line layout (time/level/logger on line one,
  message wrapping below) used by the embedded monitoring-column Logs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sMW1YZXkM7fDkdPtHpE95

* polish(web): tooltips on icon buttons + rename "monitoring column" → "monitoring sidebar" (#1661)

- Add Mantine `Tooltip`s to the icon-only controls: Client settings, Theme
  (dynamic light/dark label), the monitoring-sidebar toggle, the list-level and
  per-entry Expand/Collapse toggles, the Pin/Unpin toggle, and the Replay
  button. Labels mirror each control's existing aria-label.
- Rename the feature term "monitoring column" → "monitoring sidebar" across the
  user-facing labels (Open/Close/Resize), comments, and tests, so the UI calls
  it a sidebar consistently.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sMW1YZXkM7fDkdPtHpE95

* review: consistent sidebar wording + reuse MonitoringToggleProps (#1661)

Address the two optional notes from the PR #1662 review:
- Make the MonitoringToggle JSDoc voice consistent ("sidebar" throughout,
  no lingering "column").
- Drop ViewHeader's duplicate `MonitorToggleProps` and reuse the element's
  exported `MonitoringToggleProps` as the single source of truth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sMW1YZXkM7fDkdPtHpE95

* feat(web): slide-in/out animation for the monitoring-sidebar toggle (#1661)

The header MonitoringToggle now animates in/out via a Mantine Transition whose
in/out styles drive width + margin-left (plus opacity/translateX): as its slot
grows from 0 → the 36px icon, the flex-end header row reflows and pushes the
theme + client-settings buttons one slot to the left; the exit reverses and they
slide back over. A negative margin-left while collapsed cancels the row gap so
the theme icon stays flush-right when the toggle is absent. Only appearance/
disappearance (connect / disconnect / narrow viewport) animates — opening or
closing the sidebar leaves the toggle in place.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sMW1YZXkM7fDkdPtHpE95

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cliff Hall 2026-07-11 17:30:16 -04:00 • committed by GitHub
commit dbda70e83b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 613 additions and 440 deletions

View file

@ -37,7 +37,6 @@ const meta: Meta<typeof MonitoringScreen> = {
onChange: fn(),
searchValue: "",
onSearchChange: fn(),
onClose: fn(),
screens: demoScreens,
},
};

View file

@ -23,7 +23,6 @@ function renderScreen(overrides: Partial<MonitoringScreenProps> = {}) {
onChange: vi.fn(),
searchValue: "",
onSearchChange: vi.fn(),
onClose: vi.fn(),
screens: screens(),
...overrides,
};
@ -42,22 +41,14 @@ describe("MonitoringScreen", () => {
it("renders the controls tab row", () => {
renderScreen();
expect(screen.getByRole("radio", { name: "Logs" })).toBeInTheDocument();
expect(
screen.getByRole("button", { name: "Close monitoring column" }),
).toBeInTheDocument();
});
it("forwards tab changes and close from the controls", async () => {
it("forwards tab changes from the controls", async () => {
const user = userEvent.setup();
const onChange = vi.fn();
const onClose = vi.fn();
renderScreen({ onChange, onClose });
renderScreen({ onChange });
await user.click(screen.getByRole("radio", { name: "Network" }));
expect(onChange).toHaveBeenCalledWith("Network");
await user.click(
screen.getByRole("button", { name: "Close monitoring column" }),
);
expect(onClose).toHaveBeenCalledTimes(1);
});
it("forwards the search value and changes from the controls", async () => {

View file

@ -13,7 +13,6 @@ export interface MonitoringScreenProps {
/** Search text for the active screen; wired by the caller to its filter state. */
searchValue: string;
onSearchChange: (next: string) => void;
onClose: () => void;
/**
* The embedded screen node for each tab, keyed by tab label. The caller builds
* these (with `embedded` set) so this component stays a pure layout shell.
@ -38,7 +37,7 @@ const ScreenSlot = Stack.withProps({
});
/**
* The pinned monitoring column's content (#1616): a `MonitoringControls` tab row
* The pinned monitoring sidebar's content (#1616): a `MonitoringControls` tab row
* over the selected monitor screen. Layout-only — it wraps each supplied screen
* node in a `ScreenStage`, so switching tabs cross-fades (only the active tab's
* screen is mounted) the same way the primary pane does.
@ -49,7 +48,6 @@ export function MonitoringScreen({
onChange,
searchValue,
onSearchChange,
onClose,
screens,
}: MonitoringScreenProps) {
return (
@ -60,7 +58,6 @@ export function MonitoringScreen({
onChange={onChange}
searchValue={searchValue}
onSearchChange={onSearchChange}
onClose={onClose}
/>
<Divider />
<ScreenSlot>