refactor(ui): replace success-view divs in regenerate key modal with antd

Use Flex, Typography.Paragraph (with copyable), and Typography.Text
instead of raw divs + code block + CopyToClipboard wrapper. Drops the
direct react-copy-to-clipboard dependency in this component in favor
of antd's native copyable support.

Also fixes two test issues surfaced when running the e2e locally:
- RegenerateKeyModal.test.tsx no longer mocks react-copy-to-clipboard
  (the component no longer imports it), removing the CJS require()
  inside an ESM mock factory flagged by Greptile.
- keys.spec.ts scopes the Regenerate and Copy lookups to the modal.
  The Regenerate button has an icon whose aria-label ("sync") is
  concatenated into the button's accessible name, so an exact-match
  lookup on "Regenerate" failed; and the new Paragraph copyable
  renders a generic "Copy" button that collided with the other
  copyable fields on the key info view.
This commit is contained in:
Yuneng Jiang 2026-04-09 18:43:28 -07:00
parent e42baeb5ab
commit 15f7cc9134
No known key found for this signature in database
3 changed files with 39 additions and 85 deletions

View file

@ -61,11 +61,16 @@ test.describe("Proxy Admin - Keys", () => {
await expect(page.getByText("Back to Keys")).toBeVisible({ timeout: 10_000 });
await page.getByRole("button", { name: "Regenerate Key" }).click();
await page.getByRole("button", { name: "Regenerate", exact: true }).click();
// Scope to the modal — the Regenerate button has an icon whose aria-label
// ("sync") is concatenated into the button's accessible name, and the
// "Regenerate Key" button is still in the DOM behind the modal.
const modal = page.locator(".ant-modal:visible");
await modal.getByRole("button", { name: /Regenerate/ }).click();
// Success view shows the warning banner and a Copy button for the regenerated key
await expect(page.getByText("Save it now, you will not see it again")).toBeVisible({ timeout: 10_000 });
await expect(page.getByRole("button", { name: /Copy/ })).toBeVisible({ timeout: 10_000 });
await expect(modal.getByText("Save it now, you will not see it again")).toBeVisible({ timeout: 10_000 });
await expect(modal.getByRole("button", { name: "Copy", exact: true })).toBeVisible({ timeout: 10_000 });
});
test("Update key TPM and RPM limits", async ({ page }) => {

View file

@ -10,14 +10,6 @@ vi.mock("../networking", () => ({
regenerateKeyCall: (...args: unknown[]) => mockRegenerateKeyCall(...args),
}));
// Mock CopyToClipboard to render a simple button
vi.mock("react-copy-to-clipboard", () => ({
CopyToClipboard: ({ children, onCopy }: { children: React.ReactElement; onCopy: () => void }) => {
const React = require("react");
return React.cloneElement(children, { onClick: onCopy });
},
}));
const makeToken = (overrides: Partial<KeyResponse> = {}): KeyResponse =>
({
token: "token-hash-123",
@ -71,12 +63,7 @@ describe("RegenerateKeyModal", () => {
});
it("should display 'Never' when token has no expires", () => {
renderWithProviders(
<RegenerateKeyModal
{...defaultProps}
selectedToken={makeToken({ expires: undefined })}
/>,
);
renderWithProviders(<RegenerateKeyModal {...defaultProps} selectedToken={makeToken({ expires: undefined })} />);
expect(screen.getByText("Current expiry: Never")).toBeInTheDocument();
});
@ -119,9 +106,7 @@ describe("RegenerateKeyModal", () => {
it("should display grace period recommendation text", () => {
renderWithProviders(<RegenerateKeyModal {...defaultProps} />);
expect(
screen.getByText("Recommended: 24h to 72h for production keys"),
).toBeInTheDocument();
expect(screen.getByText("Recommended: 24h to 72h for production keys")).toBeInTheDocument();
});
it("should call regenerateKeyCall and show success view on successful regeneration", async () => {
@ -222,12 +207,7 @@ describe("RegenerateKeyModal", () => {
token: "new-token-hash",
});
renderWithProviders(
<RegenerateKeyModal
{...defaultProps}
selectedToken={makeToken({ key_alias: undefined })}
/>,
);
renderWithProviders(<RegenerateKeyModal {...defaultProps} selectedToken={makeToken({ key_alias: undefined })} />);
await user.click(screen.getByRole("button", { name: /Regenerate/ }));
await waitFor(() => {
@ -237,9 +217,7 @@ describe("RegenerateKeyModal", () => {
it("should not call regenerateKeyCall when selectedToken is null", async () => {
const user = userEvent.setup();
renderWithProviders(
<RegenerateKeyModal {...defaultProps} selectedToken={null} />,
);
renderWithProviders(<RegenerateKeyModal {...defaultProps} selectedToken={null} />);
// The form shouldn't even be populated, but we check the button doesn't trigger a call
const regenerateBtn = screen.queryByRole("button", { name: /Regenerate/ });

View file

@ -1,16 +1,13 @@
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
import { CopyOutlined, SyncOutlined } from "@ant-design/icons";
import { Alert, Button, Col, Form, Input, InputNumber, Modal, Row, Space, Typography } from "antd";
import { SyncOutlined } from "@ant-design/icons";
import { Alert, Button, Col, Flex, Form, Input, InputNumber, Modal, Row, Space, Typography } from "antd";
import { add } from "date-fns";
import { useEffect, useState } from "react";
import { CopyToClipboard } from "react-copy-to-clipboard";
import { KeyResponse } from "../key_team_helpers/key_list";
import NotificationManager from "../molecules/notifications_manager";
import { regenerateKeyCall } from "../networking";
const { Text } = Typography;
const { Text, Paragraph } = Typography;
interface RegenerateKeyModalProps {
selectedToken: KeyResponse | null;
@ -174,54 +171,27 @@ export function RegenerateKeyModal({ selectedToken, visible, onClose, onKeyUpdat
}
>
{regeneratedKey ? (
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
<Alert
type="warning"
showIcon
banner
message="Save it now, you will not see it again"
/>
<Flex vertical gap="middle">
<Alert type="warning" showIcon message="Save it now, you will not see it again" />
<div>
<div style={{ fontSize: 12, color: "#8c8c8c", marginBottom: 2 }}>Key Alias</div>
<div style={{ fontSize: 14, color: "#595959" }}>
{selectedToken?.key_alias || "No alias set"}
</div>
</div>
<Flex vertical gap={2}>
<Text type="secondary" style={{ fontSize: 12 }}>
Key Alias
</Text>
<Text>{selectedToken?.key_alias || "No alias set"}</Text>
</Flex>
<div
style={{
display: "flex",
alignItems: "center",
gap: 8,
background: "#f5f5f5",
border: "1px solid #d9d9d9",
borderRadius: 6,
padding: "10px 12px",
<Paragraph
code
copyable={{
text: regeneratedKey,
onCopy: () => NotificationManager.success("Virtual Key copied to clipboard"),
}}
style={{ marginBottom: 0, wordBreak: "break-all" }}
>
<code
style={{
flex: 1,
fontFamily: "SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace",
fontSize: 13,
color: "#262626",
wordBreak: "break-all",
lineHeight: 1.5,
}}
>
{regeneratedKey}
</code>
<CopyToClipboard
text={regeneratedKey}
onCopy={() => NotificationManager.success("Virtual Key copied to clipboard")}
>
<Button type="primary" icon={<CopyOutlined />} size="small">
Copy
</Button>
</CopyToClipboard>
</div>
</div>
{regeneratedKey}
</Paragraph>
</Flex>
) : (
<Form
form={form}
@ -261,16 +231,17 @@ export function RegenerateKeyModal({ selectedToken, visible, onClose, onKeyUpdat
name="duration"
label="Expire Key"
extra={
<>
<Flex vertical gap={2}>
<Text type="secondary" style={{ fontSize: 12 }}>
Current expiry: {selectedToken?.expires ? new Date(selectedToken.expires).toLocaleString() : "Never"}
Current expiry:{" "}
{selectedToken?.expires ? new Date(selectedToken.expires).toLocaleString() : "Never"}
</Text>
{newExpiryTime && (
<div>
<Text style={{ fontSize: 12, color: "#52c41a" }}>New expiry: {newExpiryTime}</Text>
</div>
<Text type="success" style={{ fontSize: 12 }}>
New expiry: {newExpiryTime}
</Text>
)}
</>
</Flex>
}
>
<Input placeholder="e.g. 30s, 30h, 30d" />