From 1c9d66eacdfebe4134e18383418988ce7f7530f8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 31 May 2026 02:35:39 +0000 Subject: [PATCH] fix(ui): address greptile feedback on coding-agent prompt modal - Switch logo paths from '../ui/assets/logos/' relative form to absolute '/ui/assets/logos/' so they don't break on routes whose '..' traversal lands somewhere other than the UI root (matches the convention already used in MCPLogoSelector.tsx). - Split the 'copied' state between the small icon copy button and the primary 'Copy Virtual Key' button. Clicking the icon used to flip the primary button's label to 'Copied!' even though the user never touched it, which is confusing. - Add tests that pin both behaviors (logos use absolute paths; icon click does not relabel the primary button) so future regressions fail the suite. Co-authored-by: ishaan-berri --- .../shared/CreatedKeyDisplay.test.tsx | 19 ++++++++++++ .../components/shared/CreatedKeyDisplay.tsx | 31 ++++++++++++------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx index 9dbdebfe5d1..b066c92a3e4 100644 --- a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx @@ -104,4 +104,23 @@ describe("CreatedKeyDisplay", () => { expect(screen.getByRole("button", { name: /copy virtual key/i })).toBeInTheDocument(); }); + + it("does not relabel the primary button when the icon copy button is clicked", async () => { + const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime }); + render(); + + await user.click(screen.getByRole("button", { name: /^copy api key$/i })); + + expect(screen.getByRole("button", { name: /copy virtual key/i })).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /^copied!$/i })).not.toBeInTheDocument(); + }); + + it("uses absolute /ui/assets/logos/ paths so logos resolve regardless of the current route", () => { + render(); + const images = screen.getByTestId("coding-agent-logos").querySelectorAll("img"); + + Array.from(images).forEach((img) => { + expect(img.getAttribute("src")).toMatch(/^\/ui\/assets\/logos\//); + }); + }); }); diff --git a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx index 237d23304a2..28da17d61f1 100644 --- a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx +++ b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx @@ -10,10 +10,10 @@ interface CreatedKeyDisplayProps { } const codingAgentLogos: { name: string; src: string }[] = [ - { name: "Cursor", src: "../ui/assets/logos/cursor.svg" }, - { name: "Claude Code", src: "../ui/assets/logos/anthropic.svg" }, - { name: "OpenAI Codex", src: "../ui/assets/logos/openai_small.svg" }, - { name: "GitHub Copilot", src: "../ui/assets/logos/github_copilot.svg" }, + { name: "Cursor", src: "/ui/assets/logos/cursor.svg" }, + { name: "Claude Code", src: "/ui/assets/logos/anthropic.svg" }, + { name: "OpenAI Codex", src: "/ui/assets/logos/openai_small.svg" }, + { name: "GitHub Copilot", src: "/ui/assets/logos/github_copilot.svg" }, ]; const CodingAgentLogos: React.FC = () => ( @@ -70,15 +70,22 @@ const resolveProxyBaseUrl = (): string => { }; const CreatedKeyDisplay: React.FC = ({ apiKey }) => { - const [copiedKey, setCopiedKey] = useState(false); + const [copiedKeyIcon, setCopiedKeyIcon] = useState(false); + const [copiedKeyButton, setCopiedKeyButton] = useState(false); const [copiedPrompt, setCopiedPrompt] = useState(false); const codingAgentPrompt = useMemo(() => buildCodingAgentPrompt(resolveProxyBaseUrl()), []); - const handleCopyKey = () => { - setCopiedKey(true); + const handleCopyKeyIcon = () => { + setCopiedKeyIcon(true); MessageManager.success("Key copied to clipboard"); - setTimeout(() => setCopiedKey(false), 2000); + setTimeout(() => setCopiedKeyIcon(false), 2000); + }; + + const handleCopyKeyButton = () => { + setCopiedKeyButton(true); + MessageManager.success("Key copied to clipboard"); + setTimeout(() => setCopiedKeyButton(false), 2000); }; const handleCopyPrompt = () => { @@ -110,8 +117,8 @@ const CreatedKeyDisplay: React.FC = ({ apiKey }) => {
Your API Key - - + +
- +