fix(web): collapsible tool description in ToolDetailPanel — shown by default (#1381) (#1459)

* fix(web): collapse long tool descriptions in ToolDetailPanel (#1381)

Long tool descriptions (e.g. sequential-thinking-server's "Sequential
Thinking" tool) filled the panel and pushed the form + Execute button
off-screen. The internal scroll region for the form/progress was already
in place; this adds the collapsible description.

- Wrap the description in a Mantine Collapse, collapsed by default.
- Expose the trigger as a chevron ActionIcon pinned to the right of the
  tool-name row (FaChevronRight collapsed / FaChevronDown expanded), with
  Show/Hide description aria-labels. Rendered only when a description exists.
- Reset to collapsed on tool change via the adjust-state-during-render
  pattern, mirroring how ToolsScreen clears formValues.

Tests + stories cover collapsed default, expand/collapse toggle, reset on
tool switch, and the no-description case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(web): show tool description by default, click to hide (#1381)

Most tool descriptions are short, so default to showing the description
and let the user collapse a long one via the chevron, rather than the
reverse. Flips the initial/reset state to open and updates the toggle
aria-labels, tests, and stories accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(web): use Ri disclosure chevrons in ToolDetailPanel (#1459 review)

Swap react-icons/fa FaChevronDown/FaChevronRight for the established
react-icons/ri RiArrowDownSLine/RiArrowRightSLine disclosure-chevron
convention already used in ResourceLink, keeping chevron visuals
consistent across the app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* a11y(web): wire description toggle as expandable control (#1459 review)

Add aria-expanded + aria-controls to the description chevron, tying it to
the Collapse region (via useId) so assistive tech announces it as a single
expandable control rather than two differently-labelled buttons. Adds a
test covering the wiring and the aria-expanded flip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cliff Hall 2026-06-13 19:13:29 -04:00 • committed by GitHub
commit 92da6c1675
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,5 +1,7 @@
import {
ActionIcon,
Button,
Collapse,
Divider,
Group,
Image,
@ -8,6 +10,8 @@ import {
Switch,
Text,
} from "@mantine/core";
import { useId, useState } from "react";
import { RiArrowDownSLine, RiArrowRightSLine } from "react-icons/ri";
import type {
ProgressNotification,
Tool,
@ -86,10 +90,21 @@ const ToolIcon = Image.withProps({
fit: "contain",
});
// `flex: 1` lets the title absorb the row's slack so the chevron toggle pins
// to the right edge of the (nowrap) TitleRow.
const ToolTitle = Text.withProps({
fw: 700,
size: "lg",
truncate: "end",
flex: 1,
});
// Chevron toggle for the collapsible description, pinned to the right of the
// title row. `aria-label` is set per-render since it reflects the open state.
const DescriptionToggle = ActionIcon.withProps({
variant: "subtle",
color: "gray",
size: "sm",
});
const DescriptionText = Text.withProps({
@ -145,6 +160,21 @@ export function ToolDetailPanel({
const { name, title, description, icons, annotations, inputSchema } = tool;
const iconSrc = icons?.[0]?.src;
// Descriptions are shown by default (most are short); the chevron lets the
// user hide a long one to keep the form and Execute footer in view. Reset to
// shown when switching tools (React's adjust-state-during-render pattern) so
// a prior tool's hidden state doesn't carry over — mirrors how ToolsScreen
// clears formValues on change.
const [descriptionOpen, setDescriptionOpen] = useState(true);
const [prevToolName, setPrevToolName] = useState(name);
if (name !== prevToolName) {
setPrevToolName(name);
setDescriptionOpen(true);
}
// Ties the toggle to the Collapse region so assistive tech announces it as a
// single expandable control (aria-expanded + aria-controls).
const descriptionRegionId = useId();
// Show the toggle only when the server supports task tool calls and the tool
// doesn't forbid them. `required` tools are forced on (checked + disabled);
// `optional` tools follow the user's `runAsTask` choice.
@ -166,6 +196,18 @@ export function ToolDetailPanel({
<TitleRow>
{iconSrc && <ToolIcon src={iconSrc} alt="" />}
<ToolTitle>{resolveDisplayLabel(name, title)}</ToolTitle>
{description && (
<DescriptionToggle
aria-label={
descriptionOpen ? "Hide description" : "Show description"
}
aria-expanded={descriptionOpen}
aria-controls={descriptionRegionId}
onClick={() => setDescriptionOpen((open) => !open)}
>
{descriptionOpen ? <RiArrowDownSLine /> : <RiArrowRightSLine />}
</DescriptionToggle>
)}
</TitleRow>
{hasAnyAnnotation(annotations) && annotations && (
<Group gap="xs">
@ -187,7 +229,11 @@ export function ToolDetailPanel({
<BodyScroll>
<BodyStack>
{description && <DescriptionText>{description}</DescriptionText>}
{description && (
<Collapse in={descriptionOpen} id={descriptionRegionId}>
<DescriptionText>{description}</DescriptionText>
</Collapse>
)}
<Divider />