feat(ui): migrate from HeroUI to shadcn/ui (#11532)

This commit is contained in:
Alejandro Bailo authored and GitHub committed 2026-07-08 16:57:02 +02:00
1 parent c665005790
commit 52875b5c7c
519 files changed
+4798 -6997

No files matched your search

@@ -2,7 +2,7 @@
import { ColumnDef } from "@tanstack/react-table";
import { DataTableColumnHeader } from "@/components/ui/table";
import { DataTableColumnHeader } from "@/components/shadcn/table";
import { DataTableRowActions } from "./data-table-row-actions";
import {
@@ -0,0 +1,60 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it } from "vitest";
import { DateCell, NameCell } from "./table-cells";
import type { EnrichedApiKey } from "./types";
const apiKey: EnrichedApiKey = {
type: "api-keys",
id: "api-key-1",
attributes: {
name: "Production access key with a very long human readable name",
prefix: "pk_12345678",
expires_at: "2099-01-01T00:00:00Z",
revoked: false,
inserted_at: "2026-01-01T00:00:00Z",
last_used_at: null,
},
relationships: {
entity: {
data: {
type: "users",
id: "user-1",
},
},
},
userEmail: "user@example.com",
};
describe("NameCell", () => {
it("keeps long API key names on one line with a tooltip", async () => {
// Given - A long API key name
const user = userEvent.setup();
render(<NameCell apiKey={apiKey} />);
// When - Reading and hovering the displayed name
const name = screen.getByText(apiKey.attributes.name!);
await user.hover(name);
// Then - The cell has a fixed width, truncates, and exposes the full name
expect(name).toHaveClass("w-64", "truncate", "whitespace-nowrap");
expect(await screen.findByRole("tooltip")).toHaveTextContent(
apiKey.attributes.name!,
);
});
});
describe("DateCell", () => {
it("keeps API key dates on one line", () => {
// Given - A rendered API key date
render(<DateCell date={null} />);
// When - Reading the date cell
const date = screen.getByText("Never");
// Then - The table date cannot wrap to a second line
expect(date).toHaveClass("whitespace-nowrap");
});
});
@@ -1,14 +1,35 @@
import { Chip } from "@heroui/chip";
import {
Badge,
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/shadcn";
import { FALLBACK_VALUES } from "./constants";
import { EnrichedApiKey, getApiKeyStatus } from "./types";
import { formatRelativeTime, getStatusColor, getStatusLabel } from "./utils";
export const NameCell = ({ apiKey }: { apiKey: EnrichedApiKey }) => (
<p className="text-sm font-medium">
{apiKey.attributes.name || FALLBACK_VALUES.UNNAMED}
</p>
);
// Maps HeroUI status colors to shadcn Badge variants
const STATUS_BADGE_VARIANT = {
success: "success",
danger: "error",
warning: "warning",
} as const;
export const NameCell = ({ apiKey }: { apiKey: EnrichedApiKey }) => {
const name = apiKey.attributes.name || FALLBACK_VALUES.UNNAMED;
return (
<Tooltip>
<TooltipTrigger asChild>
<p className="w-64 truncate text-sm font-medium whitespace-nowrap">
{name}
</p>
</TooltipTrigger>
<TooltipContent>{name}</TooltipContent>
</Tooltip>
);
};
export const PrefixCell = ({ apiKey }: { apiKey: EnrichedApiKey }) => (
<code className="rounded px-2 py-1 font-mono text-xs">
@@ -17,7 +38,7 @@ export const PrefixCell = ({ apiKey }: { apiKey: EnrichedApiKey }) => (
);
export const DateCell = ({ date }: { date: string | null }) => (
<p className="text-sm">{formatRelativeTime(date)}</p>
<p className="text-sm whitespace-nowrap">{formatRelativeTime(date)}</p>
);
export const LastUsedCell = ({ apiKey }: { apiKey: EnrichedApiKey }) => (
@@ -27,9 +48,9 @@ export const LastUsedCell = ({ apiKey }: { apiKey: EnrichedApiKey }) => (
export const StatusCell = ({ apiKey }: { apiKey: EnrichedApiKey }) => {
const status = getApiKeyStatus(apiKey);
return (
<Chip color={getStatusColor(status)} size="sm" variant="flat">
<Badge variant={STATUS_BADGE_VARIANT[getStatusColor(status)]}>
{getStatusLabel(status)}
</Chip>
</Badge>
);
};