Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ui/litellm-dashboard/eslint-metrics.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"@typescript-eslint/no-explicit-any": 1988,
"@typescript-eslint/no-explicit-any": 1982,
"complexity": 128,
"local/no-large-inline-object-arg": 513,
"local/no-large-inline-object-arg": 512,
"local/no-long-condition-chain": 233,
"max-depth": 59,
"no-console": 15
Expand Down
7 changes: 1 addition & 6 deletions ui/litellm-dashboard/eslint-suppressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -1650,7 +1650,7 @@
"count": 1
},
"no-restricted-imports": {
"count": 2
"count": 1
}
},
"src/components/guardrails/tool_permission/ToolPermissionRulesEditor.tsx": {
Expand Down Expand Up @@ -2491,11 +2491,6 @@
"count": 4
}
},
"src/components/view_logs/columns.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/components/view_logs/index.tsx": {
"no-restricted-imports": {
"count": 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
SortState,
TableHeaderSortDropdown,
} from "@/components/common_components/TableHeaderSortDropdown/TableHeaderSortDropdown";
import { DateCell, IdCell } from "@/components/shared/table_cells";
import { AccessGroupDetail } from "./AccessGroupsDetailsPage";
import { AccessGroupCreateModal } from "./AccessGroupsModal/AccessGroupCreateModal";
import { AccessGroup } from "./types";
Expand Down Expand Up @@ -143,21 +144,7 @@ export function AccessGroupsPage() {
header: () => <span>ID</span>,
enableSorting: false,
size: 170,
cell: ({ row }) => {
const record = row.original;
return (
<Tooltip title={record.id}>
<Text
ellipsis
className="text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs cursor-pointer"
style={{ fontSize: 14, padding: "1px 8px" }}
onClick={() => setSelectedGroupId(record.id)}
>
{record.id}
</Text>
</Tooltip>
);
},
cell: ({ row }) => <IdCell value={row.original.id} onClick={setSelectedGroupId} />,
},
{
id: "name",
Expand Down Expand Up @@ -211,15 +198,15 @@ export function AccessGroupsPage() {
header: () => <span>Created</span>,
enableSorting: true,
sortingFn: "datetime",
cell: ({ getValue }) => new Date(getValue() as string).toLocaleDateString(),
cell: ({ getValue }) => <DateCell value={getValue() as string} precision="date" />,
meta: { responsive: ["lg"] },
},
{
id: "updatedAt",
accessorKey: "updatedAt",
header: () => <span>Updated</span>,
enableSorting: false,
cell: ({ getValue }) => new Date(getValue() as string).toLocaleDateString(),
cell: ({ getValue }) => <DateCell value={getValue() as string} precision="date" />,
meta: { responsive: ["xl"] },
},
...(canModify
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import DeleteResourceModal from "@/components/common_components/DeleteResourceMo
import TableIconActionButton from "@/components/common_components/IconActionButton/TableIconActionButtons/TableIconActionButton";
import NotificationsManager from "@/components/molecules/notifications_manager";
import { useBudgets, useDeleteBudget, budgetItem } from "@/app/(dashboard)/hooks/budgets/useBudgets";
import { MoneyCell } from "@/components/shared/table_cells";
import BudgetModal from "./budget_modal";
import EditBudgetModal from "./edit_budget_modal";
import { CREATE_END_USER_CURL_COMMAND, CHAT_COMPLETIONS_CURL_COMMAND, OPENAI_SDK_PYTHON_CODE } from "./constants";
Expand Down Expand Up @@ -127,7 +128,9 @@ const BudgetPanel: React.FC<BudgetSettingsPageProps> = ({ accessToken }) => {
.map((value: budgetItem) => (
<TableRow key={value.budget_id}>
<TableCell>{value.budget_id}</TableCell>
<TableCell>{value.max_budget ? value.max_budget : "n/a"}</TableCell>
<TableCell>
<MoneyCell value={value.max_budget} decimals={2} showZero emptyText="Unlimited" />
</TableCell>
<TableCell>{value.tpm_limit ? value.tpm_limit : "n/a"}</TableCell>
<TableCell>{value.rpm_limit ? value.rpm_limit : "n/a"}</TableCell>
{canModify && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import React, { useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Button, Card, Drawer, Empty, Input, Space, Table, Tooltip, Typography, message } from "antd";
import { Button, Card, Drawer, Empty, Input, Space, Table, Typography, message } from "antd";
import type { ColumnsType } from "antd/es/table";
import {
DeleteOutlined,
Expand All @@ -13,6 +13,7 @@
SearchOutlined,
} from "@ant-design/icons";
import { MemoryRow, createMemory, deleteMemory, fetchMemoryList, updateMemory } from "@/components/networking";
import { DateCell, IdCell } from "@/components/shared/table_cells";
import { MemoryEditModal } from "./MemoryEditModal";
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";

Expand Down Expand Up @@ -43,7 +44,7 @@

const PAGE_SIZE = 50;

export const MemoryView: React.FC<MemoryViewProps> = ({ accessToken }) => {

Check warning on line 47 in ui/litellm-dashboard/src/app/(dashboard)/memory/components/MemoryView.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Arrow function has a complexity of 22. Maximum allowed is 20
const [searchInput, setSearchInput] = useState("");
const [appliedSearch, setAppliedSearch] = useState("");
const [detailRow, setDetailRow] = useState<MemoryRow | null>(null);
Expand Down Expand Up @@ -191,34 +192,13 @@
}
};

const renderIdPill = (id: string | null | undefined, onClick?: () => void) => {
if (!id) return <Text type="secondary">-</Text>;
const short = id.length > 10 ? `${id.slice(0, 7)}...` : id;
const pillClass =
"font-mono text-blue-600 bg-blue-50 text-xs font-medium px-2 py-0.5 rounded-md border border-blue-200 inline-block max-w-[15ch] truncate whitespace-nowrap";
return (
<Tooltip title={id}>
{onClick ? (
<button
onClick={onClick}
className={`${pillClass} hover:bg-blue-100 cursor-pointer transition-colors text-left`}
>
{short}
</button>
) : (
<span className={pillClass}>{short}</span>
)}
</Tooltip>
);
};

const columns: ColumnsType<MemoryRow> = [
{
title: "ID",
dataIndex: "memory_id",
key: "memory_id",
width: 140,
render: (_: unknown, r: MemoryRow) => renderIdPill(r.memory_id, () => setDetailRow(r)),
render: (_: unknown, r: MemoryRow) => <IdCell value={r.memory_id} onClick={() => setDetailRow(r)} />,
},
{
title: "Name",
Expand Down Expand Up @@ -246,21 +226,21 @@
dataIndex: "user_id",
key: "user_id",
width: 160,
render: (uid?: string | null) => renderIdPill(uid),
render: (uid?: string | null) => <IdCell value={uid} />,
},
{
title: "Team ID",
dataIndex: "team_id",
key: "team_id",
width: 160,
render: (tid?: string | null) => renderIdPill(tid),
render: (tid?: string | null) => <IdCell value={tid} />,
},
{
title: "Updated",
dataIndex: "updated_at",
key: "updated_at",
width: 180,
render: (ts?: string) => <Text type="secondary">{formatTimestamp(ts)}</Text>,
render: (ts?: string) => <DateCell value={ts} />,
// No sorter — backend already returns rows in `updated_at DESC` order,
// and a client-side sorter on a paginated view would only affect the
// current page.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Empty, Table, Tooltip } from "antd";
import type { ColumnsType } from "antd/es/table";
import type { SpinProps } from "antd";
import DefaultProxyAdminTag from "@/components/common_components/DefaultProxyAdminTag";
import { DateCell } from "@/components/shared/table_cells";

interface ProjectKeysTableProps {
keys: KeyResponse[];
Expand Down Expand Up @@ -33,13 +34,13 @@ const columns: ColumnsType<KeyResponse> = [
title: "Created",
dataIndex: "created_at",
key: "created_at",
render: (date: string) => (date ? new Date(date).toLocaleDateString() : "—"),
render: (date: string) => <DateCell value={date} precision="date" />,
},
{
title: "Last Active",
dataIndex: "last_active",
key: "last_active",
render: (date: string | null) => (date ? new Date(date).toLocaleDateString() : "Never"),
render: (date: string | null) => <DateCell value={date} precision="date" fallback="Never" />,
},
];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useProjects, ProjectResponse } from "@/app/(dashboard)/hooks/projects/useProjects";
import { useTeams } from "@/app/(dashboard)/hooks/teams/useTeams";
import { DateCell, IdCell } from "@/components/shared/table_cells";
import { LoadingOutlined, PlusOutlined } from "@ant-design/icons";
import {
Button,
Expand Down Expand Up @@ -57,7 +58,7 @@
return list.filter((p) => {
const alias = teamAliasMap.get(p.team_id ?? "") ?? "";
return (
(p.project_alias ?? "").toLowerCase().includes(lower) ||

Check warning on line 61 in ui/litellm-dashboard/src/app/(dashboard)/projects/components/ProjectsPage.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Boolean expression combines 4 conditions; extract it into a named variable
p.project_id.toLowerCase().includes(lower) ||
(p.description ?? "").toLowerCase().includes(lower) ||
alias.toLowerCase().includes(lower)
Expand All @@ -72,18 +73,7 @@
dataIndex: "project_id",
key: "project_id",
width: 170,
render: (id: string) => (
<Tooltip title={id}>
<Text
ellipsis
className="text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs cursor-pointer"
style={{ fontSize: 14, padding: "1px 8px" }}
onClick={() => setSelectedProjectId(id)}
>
{id}
</Text>
</Tooltip>
),
render: (id: string) => <IdCell value={id} onClick={setSelectedProjectId} />,
},
{
title: "Name",
Expand Down Expand Up @@ -137,14 +127,14 @@
key: "created_at",
sorter: (a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime(),
responsive: ["lg"],
render: (date: string) => new Date(date).toLocaleDateString(),
render: (date: string) => <DateCell value={date} precision="date" />,
},
{
title: "Updated",
dataIndex: "updated_at",
key: "updated_at",
responsive: ["xl"],
render: (date: string) => new Date(date).toLocaleDateString(),
render: (date: string) => <DateCell value={date} precision="date" />,
},
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow, Button } from "@tremor/react";
import { SwitchVerticalIcon, ChevronUpIcon, ChevronDownIcon, TrashIcon } from "@heroicons/react/outline";
import { Tooltip } from "antd";
import { CopyOutlined } from "@ant-design/icons";
import { PromptSpec, modelHubCall } from "@/components/networking";
import { DateCell, IdCell } from "@/components/shared/table_cells";
import {
ColumnDef,
flexRender,
Expand All @@ -27,7 +27,7 @@
interface ModelGroupInfo {
model_group: string;
providers: string[];
[key: string]: any;

Check warning on line 30 in ui/litellm-dashboard/src/app/(dashboard)/prompts/components/prompt_table.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Unexpected any. Specify a different type
}

const PromptTable: React.FC<PromptTableProps> = ({
Expand Down Expand Up @@ -62,48 +62,11 @@
fetchModelHubData();
}, [accessToken]);

// Format date helper function
const formatDate = (dateString?: string) => {
if (!dateString) return "-";
const date = new Date(dateString);
return date.toLocaleString();
};

const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text);
};

const columns: ColumnDef<PromptSpec>[] = [
{
header: "Prompt ID",
accessorKey: "prompt_id",
cell: (info: any) => {
const fullId = String(info.getValue() || "");
const displayId = fullId.length > 25 ? `${fullId.slice(0, 25)}...` : fullId;
return (
<div className="flex items-center gap-2">
<Tooltip title={fullId}>
<Button
size="xs"
variant="light"
className="font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal px-2 py-0.5 text-left overflow-hidden truncate min-w-[220px] justify-start"
onClick={() => info.getValue() && onPromptClick?.(info.getValue())}
>
{displayId}
</Button>
</Tooltip>
<Tooltip title="Copy prompt ID">
<CopyOutlined
onClick={(e) => {
e.stopPropagation();
copyToClipboard(fullId);
}}
className="cursor-pointer text-gray-500 hover:text-blue-500 text-xs"
/>
</Tooltip>
</div>
);
},
cell: (info: any) => <IdCell value={info.getValue()} onClick={onPromptClick} copyable />,

Check warning on line 69 in ui/litellm-dashboard/src/app/(dashboard)/prompts/components/prompt_table.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Unexpected any. Specify a different type
},
{
header: "Model",
Expand All @@ -125,7 +88,7 @@
{/* Provider Icon */}
<div className="shrink-0">
{provider && logo ? (
<img

Check warning on line 91 in ui/litellm-dashboard/src/app/(dashboard)/prompts/components/prompt_table.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src={logo}
alt={`${provider} logo`}
className="w-4 h-4"
Expand Down Expand Up @@ -162,26 +125,12 @@
{
header: "Created At",
accessorKey: "created_at",
cell: ({ row }) => {
const prompt = row.original;
return (
<Tooltip title={prompt.created_at}>
<span className="text-xs">{formatDate(prompt.created_at)}</span>
</Tooltip>
);
},
cell: ({ row }) => <DateCell value={row.original.created_at} />,
},
{
header: "Updated At",
accessorKey: "updated_at",
cell: ({ row }) => {
const prompt = row.original;
return (
<Tooltip title={prompt.updated_at}>
<span className="text-xs">{formatDate(prompt.updated_at)}</span>
</Tooltip>
);
},
cell: ({ row }) => <DateCell value={row.original.updated_at} />,
},
{
header: "Environment",
Expand Down Expand Up @@ -225,7 +174,7 @@
header: "Actions",
id: "actions",
enableSorting: false,
cell: ({ row }: any) => {

Check warning on line 177 in ui/litellm-dashboard/src/app/(dashboard)/prompts/components/prompt_table.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Unexpected any. Specify a different type
const prompt = row.original;
const promptName = prompt.prompt_id || "Unknown Prompt";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Tag } from "antd";
import { ColumnsType } from "antd/es/table";
import TableIconActionButton from "@/components/common_components/IconActionButton/TableIconActionButtons/TableIconActionButton";
import { DateCell, IdCell } from "@/components/shared/table_cells";
import { SearchTool } from "./types";

export const searchToolColumns = (
Expand All @@ -20,14 +21,7 @@ export const searchToolColumns = (
return <span className="text-xs">-</span>;
}

return (
<button
onClick={() => onView(tool.search_tool_id!)}
className="font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal px-2 py-0.5 text-left cursor-pointer max-w-40"
>
<span className="truncate block">{tool.search_tool_id}</span>
</button>
);
return <IdCell value={tool.search_tool_id} onClick={onView} />;
},
},
{
Expand All @@ -52,15 +46,15 @@ export const searchToolColumns = (
dataIndex: "created_at",
key: "created_at",
render: (_, tool) => {
return <span className="text-xs">{tool.created_at ? new Date(tool.created_at).toLocaleDateString() : "-"}</span>;
return <DateCell value={tool.created_at} precision="date" />;
},
},
{
title: "Updated At",
dataIndex: "updated_at",
key: "updated_at",
render: (_, tool) => {
return <span className="text-xs">{tool.updated_at ? new Date(tool.updated_at).toLocaleDateString() : "-"}</span>;
return <DateCell value={tool.updated_at} precision="date" />;
},
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
}));

vi.mock("./user_edit_view", () => ({
UserEditView: ({ onSubmit, onCancel }: { onSubmit: (values: any) => void; onCancel: () => void }) => (

Check warning on line 14 in ui/litellm-dashboard/src/app/(dashboard)/users/_components/BulkEditUsers.test.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Unexpected any. Specify a different type
<div data-testid="user-edit-view">
<button onClick={() => onSubmit({ user_role: "admin", max_budget: 100 })}>Submit</button>
<button onClick={onCancel}>Cancel</button>
Expand Down Expand Up @@ -47,7 +47,7 @@
describe("BulkEditUserModal", () => {
beforeEach(() => {
vi.clearAllMocks();
mockUserBulkUpdateUserCall.mockResolvedValue({

Check warning on line 50 in ui/litellm-dashboard/src/app/(dashboard)/users/_components/BulkEditUsers.test.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Object literal with 4 properties passed inline as an argument; assign it to a named variable first
results: [],
total_requested: 2,
successful_updates: 2,
Expand Down Expand Up @@ -91,7 +91,7 @@
it("should display budget information in table", () => {
renderWithProviders(<BulkEditUserModal {...defaultProps} />);

expect(screen.getByText("$50")).toBeInTheDocument();
expect(screen.getByText("$50.00")).toBeInTheDocument();
expect(screen.getByText("Unlimited")).toBeInTheDocument();
});

Expand Down
Loading
Loading