feat(site/src/pages/AgentsPage): add copy button to ProposePlanTool (#23940)

Reuse the CopyButton component to let users copy plan content from
the propose_plan tool output. Follows the same pattern used by the
assistant message copy button.
This commit is contained in:
Mathias Fredriksson
2026-04-02 14:30:36 +03:00
committed by GitHub
parent 16add93908
commit aa5ec0bfcc
2 changed files with 39 additions and 2 deletions
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { expect, spyOn, within } from "storybook/test";
import { expect, spyOn, userEvent, within } from "storybook/test";
import { reactRouterParameters } from "storybook-addon-remix-react-router";
import { API } from "#/api/api";
import { Tool } from "./Tool";
@@ -79,6 +79,9 @@ export const Completed: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(await canvas.findByText("Implementation Plan")).toBeInTheDocument();
expect(
canvas.getByRole("button", { name: "Copy plan" }),
).toBeInTheDocument();
},
};
@@ -100,6 +103,34 @@ export const CustomPath: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(await canvas.findByText("Implementation Plan")).toBeInTheDocument();
expect(
canvas.getByRole("button", { name: "Copy plan" }),
).toBeInTheDocument();
},
};
export const CompletedCopyButton: Story = {
args: {
status: "completed",
args: { path: "/home/coder/PLAN.md" },
result: {
ok: true,
path: "/home/coder/PLAN.md",
kind: "plan",
file_id: "test-file-id-copy",
media_type: "text/markdown",
},
},
beforeEach: () => {
spyOn(API.experimental, "getChatFileText").mockResolvedValue(samplePlan);
spyOn(navigator.clipboard, "writeText").mockResolvedValue(undefined);
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await canvas.findByText("Implementation Plan");
const copyBtn = canvas.getByRole("button", { name: "Copy plan" });
await userEvent.click(copyBtn);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(samplePlan);
},
};
@@ -2,6 +2,7 @@ import { LoaderIcon, TriangleAlertIcon } from "lucide-react";
import type React from "react";
import { useQuery } from "react-query";
import { API } from "#/api/api";
import { CopyButton } from "#/components/CopyButton/CopyButton";
import {
Tooltip,
TooltipContent,
@@ -78,7 +79,12 @@ export const ProposePlanTool: React.FC<{
)}
</div>
{displayContent ? (
<Response>{displayContent}</Response>
<>
<Response>{displayContent}</Response>
<div className="flex">
<CopyButton text={displayContent} label="Copy plan" />
</div>
</>
) : (
!fetchLoading &&
!effectiveError && (