web: Group tool-result resource_links in a scrollable "Resource Links" box with Protocol colors (#1686)
* web: Group tool-result resource_links in a scrollable "Resource Links" box with Protocol colors Closes #1685 - ToolResultPanel: coalesce consecutive `resource_link` blocks into a single bordered, internally-scrollable "Resource Links" box (mirroring the "Messages" box in the Protocol monitoring sidebar). Non-link blocks and non-adjacent runs are preserved in order via `segmentContent`. - ResourceLink: render each link card on the recessed `inset` surface (`Card variant="inset"`), matching ProtocolEntry's colors in light and dark modes; nested read-result Code blocks read as raised on the grey card via the inset cascade variable. - Drop redundant metadata: the resource `description` line (ResourceLinkInfo, and thus ContentViewer/ResourceLink) and the green "Resource:" label above the expanded read result. - Update tests + stories for the removed props/label and the new grouping box; add multi-link and split-run coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE * web: keep the resource_link description; only drop the "Resource:" label Reverts the description removal from the previous commit per review — the `description` line is retained on ResourceLinkInfo (and its ContentViewer / ResourceLink callers). Only the redundant green "Resource:" label above the expanded read result stays removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE * web: drop the resource_link description from the link cards The `description` is generated by the server and can be misleading — e.g. a blob resource served with a `text/plain` mimeType gets described as a "plaintext resource" even though the payload is a blob. Rather than surface that nonsense text, drop the description line from ResourceLinkInfo (and its ContentViewer / ResourceLink callers) entirely. Reverts the description-retention from the prior commit; the grouped "Resource Links" box and the "Resource:" label removal are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE * web: refine resource-link cards — URI-below-name + copy, ProtocolEntry toggle, full-height box Follow-up refinements to the Resource Links display: - ResourceLinkInfo: move the URI below the name and add a CopyButton beside it so the URI can be copied. The name + MIME badge (and the optional expand control) sit on the header row; the URI + copy sit on the row below. - ResourceLink: replace the bespoke chevron with the same tooltip'd ExpandToggle used by ProtocolEntry, and animate the read-result panel with Mantine's Collapse (same as ProtocolEntry). The toggle is a sibling of the URI copy button (no card-wide wrapping button) so the two real buttons never nest (axe `nested-interactive`). - ToolResultPanel: when a result contains a Resource Links box, fill the card's height so the box grows into the available space and scrolls internally (pinned "Resource Links" heading), instead of capping at a fixed content height. Plain text/image results keep the scroll-within-card body. - ToolsScreen: give the result card `flex: 1` so it fills the pane, providing the definite height the Resource Links box grows into. - Tests/stories updated for the new layout, the Expand/Collapse toggle labels, the mounted-through-collapse read result, and the full-height box (with a height-bounded decorator on the ResourceLinks story). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE * web: align resource-link card with ProtocolEntry — toggle row, badge, URI style Bring ResourceLinkInfo closer to the ProtocolEntry message card: - Move the expand/collapse toggle to the second (URI) row, opposite the copy button — mirroring ProtocolEntry, whose toggle sits on the row below the badges. The MIME badge stays on the header row's right, beside the name. - MIME badge: bump to `size="md"` so the lowercase MIME text matches the point size of ProtocolEntry's uppercase method/status badges, and make it a solid dark-blue fill with white text in dark mode (keeping the blue-light tint in light mode) instead of a washed-out translucent chip. - Render the URI like ProtocolEntry/NetworkEntry render URLs — `sm` / `fw: 500` in the default sans-serif face and text color — rather than a blue monospace "link". `monoBreak` is kept only for long-URI wrapping. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE * web: scope result-card fill to resource-link results (review follow-up) Code-review finding: ToolsScreen gave the result card `flex={1}` unconditionally, so plain text/image/error results also filled the full pane height — leaving a tall empty card and a height jump versus the input-form state. Fill is only needed so a "Resource Links" box can grow and scroll. Gate the fill on a new `resultHasResourceLinks(result)` helper (extracted to `toolResultUtils.ts` so the component module keeps exporting only components, per react-refresh/only-export-components). Non-link results keep their content-sized card; link results still fill and scroll internally. Tests: unit tests for the helper (link / text-only / empty / error) and a ToolsScreen test that a resource-link result renders the Resource Links box (covering the `flex={1}` branch). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE * web: prettier-format the resultHasResourceLinks error-case test fixture The error-case fixture in ToolResultPanel.test.tsx wasn't re-formatted after adding the required `name` field, failing CI's `format:check`. No logic change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE * web: cap a non-link block above the Resource Links box at 50% height Addresses the mixed-content case from the review: a long text block preceding the links would take its full natural height and push the Resource Links box almost entirely off-screen (only the first card peeking at the bottom). In the links-containing result, wrap each non-link block in a ScrollArea.Autosize capped at `mah: 50%` (flex "0 1 auto"), so it scrolls within at most half the card and the links box keeps the rest. A short block still takes only its content height; a result with no links renders non-link blocks uncapped in the outer scroll body as before. Adds a `ResourceLinksWithLongText` story (full-height decorator) exercising the cap. Verified visually: the text scrolls within ~50% and the links box fills the remainder. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE * web: address review — expand-toggle a11y, stale JSDoc, stronger fill test Review follow-ups on PR #1686: - ExpandToggle: add an optional `ariaLabel` (defaults to the tooltip verb, so ProtocolEntry/NetworkEntry/Task are unchanged) and expose `aria-expanded`. ResourceLink passes a per-resource label ("Expand/Collapse resource <uri>") so multiple link toggles are distinguishable to assistive tech and announce their state — restoring the a11y the card-wide button previously provided, while keeping the visible tooltip a plain "Expand"/"Collapse". - ResourceLinkInfo: fix the stale JSDoc that still described the URI as "monospace, link-styled" — it now renders sans-serif sm/fw:500 default color. - ToolsScreen test: assert the result card actually gets `flex: 1` for a links result and NOT for a plain text result, so the test verifies the fill branch it names rather than only that the heading renders. Tests: ExpandToggle gains ariaLabel + aria-expanded cases; ResourceLink / ToolResultPanel / stories updated for the per-resource toggle name. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE * web: restore cli/tui/launcher package-locks accidentally committed These lock files were touched by a local install in the worktree (dropping the `version` field and adding optional @emnapi platform deps); they are unrelated to this PR. Restore them to their v2/main state. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwZGbocZ64yN9bgb2mj1qE --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8d33e76f97
commit
8f70b60725
2 changed files with 591 additions and 197 deletions
|
|
@ -163,7 +163,7 @@ describe("ToolsScreen", () => {
|
|||
expect(screen.queryByText("Results")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders the result panel when callState has a result", () => {
|
||||
it("renders a content-sized result card for a plain text result", () => {
|
||||
renderWithMantine(
|
||||
<ToolsScreen
|
||||
{...baseProps}
|
||||
|
|
@ -174,6 +174,34 @@ describe("ToolsScreen", () => {
|
|||
/>,
|
||||
);
|
||||
expect(screen.getByText("Results")).toBeInTheDocument();
|
||||
// No links → the result card is NOT flex-filled (sizes to content).
|
||||
const card = screen.getByText("Results").closest(".mantine-Card-root");
|
||||
expect(card).not.toHaveStyle({ flex: "1" });
|
||||
});
|
||||
|
||||
it("fills the result card with a Resource Links box when the result has links", () => {
|
||||
// A resource_link result takes the full-height (`flex={1}`) card branch so
|
||||
// the Resource Links box can grow and scroll within.
|
||||
renderWithMantine(
|
||||
<ToolsScreen
|
||||
{...baseProps}
|
||||
callState={{
|
||||
status: "ok",
|
||||
result: {
|
||||
content: [
|
||||
{ type: "resource_link", uri: "demo://r/1", name: "Linked" },
|
||||
],
|
||||
},
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Resource Links" }),
|
||||
).toBeInTheDocument();
|
||||
// Links → the result card fills the pane (`flex: 1`), distinguishing this
|
||||
// branch from the content-sized text-result card above.
|
||||
const card = screen.getByText("Results").closest(".mantine-Card-root");
|
||||
expect(card).toHaveStyle({ flex: "1" });
|
||||
});
|
||||
|
||||
it("invokes onCallTool with form values on Execute", async () => {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
type ToolProgress,
|
||||
} from "../../groups/ToolDetailPanel/ToolDetailPanel";
|
||||
import { ToolResultPanel } from "../../groups/ToolResultPanel/ToolResultPanel";
|
||||
import { resultHasResourceLinks } from "../../groups/ToolResultPanel/toolResultUtils";
|
||||
import { collectSchemaDefaults } from "../../../utils/jsonUtils";
|
||||
|
||||
export interface ToolCallState {
|
||||
|
|
@ -181,7 +182,14 @@ export function ToolsScreen({
|
|||
// `result` (App.tsx), so the executing form (progress + cancel) shows
|
||||
// until the result lands.
|
||||
<ContentPane mah={SCROLL_MAX_HEIGHT}>
|
||||
<ContentCard>
|
||||
{/* Fill the pane's full height only when the result renders a
|
||||
"Resource Links" box, so that box can expand into the available
|
||||
space and scroll within. Plain text/image/error results keep the
|
||||
content-sized card (matching the input-form state) instead of
|
||||
reserving a tall empty card. */}
|
||||
<ContentCard
|
||||
flex={resultHasResourceLinks(callState.result) ? 1 : undefined}
|
||||
>
|
||||
<ToolResultPanel
|
||||
result={callState.result}
|
||||
onClear={() => onClearResult?.()}
|
||||
|
|
|
|||
Loading…
Reference in a new issue