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 <ishaan-berri@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-05-31 02:35:39 +00:00
parent 99ad65f2a2
commit 1c9d66eacd
No known key found for this signature in database
2 changed files with 38 additions and 12 deletions

View file

@ -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(<CreatedKeyDisplay apiKey="sk-test-123" />);
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(<CreatedKeyDisplay apiKey="sk-test-123" />);
const images = screen.getByTestId("coding-agent-logos").querySelectorAll("img");
Array.from(images).forEach((img) => {
expect(img.getAttribute("src")).toMatch(/^\/ui\/assets\/logos\//);
});
});
});

View file

@ -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<CreatedKeyDisplayProps> = ({ 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<CreatedKeyDisplayProps> = ({ apiKey }) => {
<div className="rounded-md border mb-4" style={{ borderColor: "#e5e7eb", background: "#fafafa" }}>
<div className="flex items-center justify-between px-3 pt-3 pb-1">
<span className="text-sm font-medium text-gray-700">Your API Key</span>
<Tooltip title={copiedKey ? "Copied!" : "Copy API key"}>
<CopyToClipboard text={apiKey} onCopy={handleCopyKey}>
<Tooltip title={copiedKeyIcon ? "Copied!" : "Copy API key"}>
<CopyToClipboard text={apiKey} onCopy={handleCopyKeyIcon}>
<Button type="text" size="small" aria-label="Copy API key" icon={<CopyOutlined />} />
</CopyToClipboard>
</Tooltip>
@ -162,9 +169,9 @@ const CreatedKeyDisplay: React.FC<CreatedKeyDisplayProps> = ({ apiKey }) => {
</div>
</div>
<CopyToClipboard text={apiKey} onCopy={handleCopyKey}>
<CopyToClipboard text={apiKey} onCopy={handleCopyKeyButton}>
<Button type="primary" style={{ marginTop: 16 }}>
{copiedKey ? "Copied!" : "Copy Virtual Key"}
{copiedKeyButton ? "Copied!" : "Copy Virtual Key"}
</Button>
</CopyToClipboard>
</div>