mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
feat(ui): link the Organization and Deleted By cells on Deleted Teams (#40751)
* feat(ui): link the Organization and Deleted By cells on Deleted Teams Both columns rendered as plain text, so tracing a deleted team back to its org or to whoever removed it meant copying an id into another page's search box. Route them through IdentityCell with orgDetailHref and userDetailHref. Team ID stays unlinked because the team itself is gone. Claude-Session: https://claude.ai/code/session_01NfwfQhamRNnSqgXMUjf3h4 * test(ui): mount a router mock for the Deleted Teams page test The page test renders the table, and the newly linked cells call useRouter, which throws without an App Router mounted. Matches how the other 35 test files in the suite stub next/navigation. Claude-Session: https://claude.ai/code/session_01NfwfQhamRNnSqgXMUjf3h4
This commit is contained in:
parent
c53f72c764
commit
b27d2cce77
3 changed files with 41 additions and 11 deletions
|
|
@ -5,6 +5,8 @@ import { renderWithProviders } from "../../../tests/test-utils";
|
|||
import DeletedTeamsPage from "./DeletedTeamsPage";
|
||||
import { useDeletedTeams, DeletedTeam } from "@/app/(dashboard)/hooks/teams/useTeams";
|
||||
|
||||
vi.mock("next/navigation", () => ({ useRouter: () => ({ push: vi.fn() }) }));
|
||||
|
||||
vi.mock("@/app/(dashboard)/hooks/teams/useTeams", () => ({
|
||||
useDeletedTeams: vi.fn(),
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import { renderWithProviders } from "../../../../tests/test-utils";
|
|||
import { DeletedTeamsTable } from "./DeletedTeamsTable";
|
||||
import { DeletedTeam } from "@/app/(dashboard)/hooks/teams/useTeams";
|
||||
|
||||
vi.mock("next/navigation", () => ({ useRouter: () => ({ push: vi.fn() }) }));
|
||||
|
||||
const makeDeletedTeam = (overrides: Partial<DeletedTeam> = {}): DeletedTeam => ({
|
||||
team_id: "team-1",
|
||||
team_alias: "Test Team",
|
||||
|
|
@ -81,3 +83,21 @@ it("renders the shared pagination footer with the server row count", () => {
|
|||
expect(screen.getByTestId("pagination-prev")).toBeEnabled();
|
||||
expect(screen.getByTestId("pagination-next")).toBeDisabled();
|
||||
});
|
||||
|
||||
it("links the organization and deleted by cells, leaving the deleted team id unlinked", () => {
|
||||
renderWithProviders(
|
||||
<DeletedTeamsTable teams={[makeDeletedTeam()]} isLoading={false} rowCount={1} {...paginationProps} />,
|
||||
);
|
||||
|
||||
expect(screen.getByRole("link", { name: "org-1" })).toHaveAttribute("href", "/ui/organizations?org=org-1");
|
||||
expect(screen.getByRole("link", { name: "user-1" })).toHaveAttribute("href", "/ui/users?user=user-1");
|
||||
expect(screen.queryByRole("link", { name: "team-1" })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("leaves the default_user_id placeholder unlinked in the deleted by cell", () => {
|
||||
const team = makeDeletedTeam({ deleted_by: "default_user_id", organization_id: null });
|
||||
renderWithProviders(<DeletedTeamsTable teams={[team]} isLoading={false} rowCount={1} {...paginationProps} />);
|
||||
|
||||
expect(screen.getByText("default_user_id")).toBeInTheDocument();
|
||||
expect(screen.queryByRole("link", { name: "default_user_id" })).not.toBeInTheDocument();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,8 +3,20 @@
|
|||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
import { DataTableSortHeader } from "@/components/shared/DataTable";
|
||||
import { DateCell, IdCell, ModelsCell, MoneyCell } from "@/components/shared/table_cells";
|
||||
import { DateCell, IdCell, IdentityCell, ModelsCell, MoneyCell } from "@/components/shared/table_cells";
|
||||
import { DeletedTeam } from "@/app/(dashboard)/hooks/teams/useTeams";
|
||||
import { orgDetailHref, userDetailHref } from "@/utils/entityLinks";
|
||||
|
||||
function EntityCell({ value, href }: { value: string | null | undefined; href: string | undefined }) {
|
||||
if (!value) {
|
||||
return <span className="text-muted-foreground">-</span>;
|
||||
}
|
||||
return (
|
||||
<span className="block max-w-60" title={value}>
|
||||
<IdentityCell title={value} titleClassName="font-normal" href={href} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export const getDeletedTeamsTableColumns = (): ColumnDef<DeletedTeam>[] => [
|
||||
{
|
||||
|
|
@ -78,7 +90,10 @@ export const getDeletedTeamsTableColumns = (): ColumnDef<DeletedTeam>[] => [
|
|||
header: "Organization",
|
||||
size: 150,
|
||||
enableSorting: false,
|
||||
cell: ({ row }) => <IdCell value={row.original.organization_id} variant="plain" />,
|
||||
cell: ({ row }) => {
|
||||
const orgId = row.original.organization_id;
|
||||
return <EntityCell value={orgId} href={orgId ? orgDetailHref(orgId) : undefined} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "deleted_at",
|
||||
|
|
@ -97,15 +112,8 @@ export const getDeletedTeamsTableColumns = (): ColumnDef<DeletedTeam>[] => [
|
|||
size: 120,
|
||||
enableSorting: false,
|
||||
cell: ({ row }) => {
|
||||
const value = row.original.deleted_by;
|
||||
if (!value) {
|
||||
return <span className="text-muted-foreground">-</span>;
|
||||
}
|
||||
return (
|
||||
<span className="block max-w-60 truncate" title={value}>
|
||||
{value}
|
||||
</span>
|
||||
);
|
||||
const deletedBy = row.original.deleted_by;
|
||||
return <EntityCell value={deletedBy} href={deletedBy ? userDetailHref(deletedBy) : undefined} />;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue