litellm/ui/litellm-dashboard/src/utils/entityLinks.test.ts
ryan-crabbe-berri 71d1bfb70a feat(ui): link the User, Team and Created By cells on the Virtual Keys page
The key detail page already walks out to the user, team and org behind a key,
but the Virtual Keys table rendered those same values as dead text, so getting
to a team meant copying its alias and searching the Teams page.

User, Team and Created By now render through the shared IdentityCell with an
href, the same hover-highlight-and-chevron affordance the Key column already
uses.

Sentinel ids do not get a link, since they have no detail page to open.
Rather than repeat that check at every call site, teamDetailHref and
userDetailHref now return undefined for "litellm-dashboard" and
"default_user_id", the way modelGroupHref already does for model grants, and
EntityLink falls back to plain text when it has no href, the way BadgeLink
already does. Both sentinels move into src/utils/sentinels.ts instead of
staying as string literals scattered across components.

Claude-Session: https://claude.ai/code/session_01NfwfQhamRNnSqgXMUjf3h4
2026-09-10 15:55:03 -07:00

41 lines
1.5 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
vi.mock("@/components/networking", () => ({ serverRootPath: "" }));
import { modelGroupHref, teamDetailHref, userDetailHref } from "./entityLinks";
describe("userDetailHref", () => {
it("targets the users page filtered to the encoded user id", () => {
expect(userDetailHref("user-1")).toMatch(/\/users\?user=user-1$/);
expect(userDetailHref("a b/c")).toMatch(/\?user=a%20b%2Fc$/);
});
it("returns no href for the proxy admin placeholder, which has no user page", () => {
expect(userDetailHref("default_user_id")).toBeUndefined();
});
});
describe("teamDetailHref", () => {
it("targets the teams page filtered to the encoded team id", () => {
expect(teamDetailHref("team-1")).toMatch(/\/teams\?team=team-1$/);
expect(teamDetailHref("a b/c")).toMatch(/\?team=a%20b%2Fc$/);
});
it("returns no href for the Admin UI session team, which has no team page", () => {
expect(teamDetailHref("litellm-dashboard")).toBeUndefined();
});
});
describe("modelGroupHref", () => {
it("targets the models page filtered to the encoded model group", () => {
expect(modelGroupHref("gpt-4.1")).toMatch(/\/models-and-endpoints\?model_group=gpt-4\.1$/);
expect(modelGroupHref("openai/*")).toMatch(/\?model_group=openai%2F\*$/);
});
it.each(["all-proxy-models", "all-team-models", "no-default-models"])(
"returns no href for the %s grant sentinel",
(sentinel) => {
expect(modelGroupHref(sentinel)).toBeUndefined();
},
);
});