mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
feat(ui): make LiteAdmin enterprise-only (#44399)
This commit is contained in:
parent
f0abe1bea1
commit
4732647de2
4 changed files with 61 additions and 5 deletions
|
|
@ -204,7 +204,7 @@ const UserDropdown: React.FC<UserDropdownProps> = ({ onLogout, variant = "navbar
|
|||
aria-label="Toggle hide bouncing icon"
|
||||
/>
|
||||
</div>
|
||||
{canUseLiteAdmin && (
|
||||
{premiumUser === true && canUseLiteAdmin && (
|
||||
<div className="flex w-full items-center justify-between gap-2">
|
||||
<span className="text-muted-foreground">Hide LiteAdmin</span>
|
||||
<Switch
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ const SidebarAccountMenu: React.FC<SidebarAccountMenuProps> = ({ onLogout, colla
|
|||
/>
|
||||
</div>
|
||||
))}
|
||||
{canUseLiteAdmin && (
|
||||
{premiumUser === true && canUseLiteAdmin && (
|
||||
<div className="flex h-[38px] items-center justify-between gap-3 px-3">
|
||||
<span className="text-[13px] text-foreground">Hide LiteAdmin</span>
|
||||
<Switch
|
||||
|
|
|
|||
|
|
@ -63,13 +63,18 @@ function deferred<T>() {
|
|||
return { promise, resolve };
|
||||
}
|
||||
|
||||
function session(role = "proxy_admin", user = "first-admin") {
|
||||
function session(
|
||||
role = "proxy_admin",
|
||||
user = "first-admin",
|
||||
license: { premium_user?: boolean | null | string } = { premium_user: true },
|
||||
) {
|
||||
const encode = (value: object) =>
|
||||
btoa(JSON.stringify(value)).replaceAll("=", "").replaceAll("+", "-").replaceAll("/", "_");
|
||||
const claims = {
|
||||
key: `sk-session-${user}`,
|
||||
user_id: user,
|
||||
user_role: role,
|
||||
...license,
|
||||
auth_header_name: "X-Gateway-Session",
|
||||
exp: Date.now() / 1000 + 3600,
|
||||
};
|
||||
|
|
@ -197,7 +202,7 @@ describe("LiteAdmin in the gateway", () => {
|
|||
it.each([
|
||||
["sidebar", SidebarAccountMenu],
|
||||
["navbar", UserDropdown],
|
||||
] as const)("persists Hide LiteAdmin from the %s account menu", async (_name, Menu) => {
|
||||
] as const)("persists Hide LiteAdmin only for enterprise users in the %s account menu", async (_name, Menu) => {
|
||||
gateway([]);
|
||||
const user = userEvent.setup();
|
||||
const view = renderWidget(Menu);
|
||||
|
|
@ -219,6 +224,57 @@ describe("LiteAdmin in the gateway", () => {
|
|||
expect(savedToggle).toBeChecked();
|
||||
await user.click(savedToggle);
|
||||
expect(await screen.findByRole("button", { name: "LiteAdmin" })).toBeInTheDocument();
|
||||
|
||||
for (const premiumUser of [false, null, undefined, "true"]) {
|
||||
session("proxy_admin", "first-admin", { premium_user: premiumUser });
|
||||
restored.refresh();
|
||||
expect(screen.getByRole("switch", { name: "Toggle hide all prompts" })).toBeInTheDocument();
|
||||
expect(screen.queryByRole("switch", { name: "Toggle hide LiteAdmin" })).not.toBeInTheDocument();
|
||||
}
|
||||
});
|
||||
|
||||
it.each([false, null, undefined, "true"])(
|
||||
"does not expose LiteAdmin when premium_user is %s",
|
||||
async (premiumUser) => {
|
||||
session("proxy_admin", "first-admin", { premium_user: premiumUser });
|
||||
const requests = gateway([]);
|
||||
const { client } = renderWidget();
|
||||
await screen.findByText("Session ready");
|
||||
await waitFor(() => expect(client.isFetching()).toBe(0));
|
||||
expect(screen.queryByRole("button", { name: "LiteAdmin" })).not.toBeInTheDocument();
|
||||
for (const modifiers of [{ metaKey: true }, { ctrlKey: true }]) {
|
||||
expect(fireEvent.keyDown(document, { key: "j", ...modifiers })).toBe(true);
|
||||
expect(screen.queryByRole("complementary", { name: "LiteAdmin" })).not.toBeInTheDocument();
|
||||
}
|
||||
expect(requests.every((request) => request.url.endsWith("/litellm-ui-config"))).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
it("removes an open panel and shortcuts when enterprise access is lost and restores it closed", async () => {
|
||||
const requests = gateway([]);
|
||||
const view = renderWidget();
|
||||
await openWidget();
|
||||
fireEvent.change(screen.getByPlaceholderText("Ask LiteAdmin…"), { target: { value: "Previous enterprise draft" } });
|
||||
await waitFor(() => expect(view.client.isFetching()).toBe(0));
|
||||
const requestCount = requests.length;
|
||||
|
||||
session("proxy_admin", "first-admin", { premium_user: false });
|
||||
view.refresh();
|
||||
expect(screen.queryByRole("button", { name: "LiteAdmin" })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole("complementary", { name: "LiteAdmin" })).not.toBeInTheDocument();
|
||||
for (const modifiers of [{ metaKey: true }, { ctrlKey: true }]) {
|
||||
expect(fireEvent.keyDown(document, { key: "j", ...modifiers })).toBe(true);
|
||||
expect(screen.queryByRole("complementary", { name: "LiteAdmin" })).not.toBeInTheDocument();
|
||||
}
|
||||
expect(requests).toHaveLength(requestCount);
|
||||
|
||||
session();
|
||||
view.refresh();
|
||||
expect(await screen.findByRole("button", { name: "LiteAdmin" })).toHaveAttribute("aria-expanded", "false");
|
||||
expect(screen.queryByRole("complementary", { name: "LiteAdmin" })).not.toBeInTheDocument();
|
||||
fireEvent.keyDown(document, { key: "j", ctrlKey: true });
|
||||
expect(await screen.findByRole("complementary", { name: "LiteAdmin" })).toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText("Ask LiteAdmin…")).toHaveValue("");
|
||||
});
|
||||
|
||||
it("isolates Hide LiteAdmin by admin and gateway and reacts to another tab clearing it", async () => {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const LiteAdminContext = createContext<LiteAdminState | null>(null);
|
|||
function useLiteAdminSession() {
|
||||
const auth = useAuthorized();
|
||||
const [disabled] = useDisableLiteAdmin(auth.userId);
|
||||
const sessionReady = !auth.isLoading && auth.isAuthorized;
|
||||
const sessionReady = !auth.isLoading && auth.isAuthorized && auth.premiumUser === true;
|
||||
const writableAdmin = !auth.isViewOnly && isProxyAdminRole(auth.userRole);
|
||||
const allowed = sessionReady && writableAdmin && !disabled;
|
||||
if (!allowed || !auth.token || !auth.accessToken) return null;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue