From 2a6877ab1da152ead03f290181ef6fa04eb157a2 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 12 Aug 2026 16:17:36 -0700 Subject: [PATCH] refactor(ui): migrate guardrails monitor table to shared DataTable --- ui/litellm-dashboard/eslint-suppressions.json | 4 +- .../_components/GuardrailsOverview.tsx | 193 ++++++++++-------- 2 files changed, 108 insertions(+), 89 deletions(-) diff --git a/ui/litellm-dashboard/eslint-suppressions.json b/ui/litellm-dashboard/eslint-suppressions.json index 8a86305b4cb..326183c5fb4 100644 --- a/ui/litellm-dashboard/eslint-suppressions.json +++ b/ui/litellm-dashboard/eslint-suppressions.json @@ -326,10 +326,10 @@ }, "src/app/(dashboard)/guardrails-monitor/_components/GuardrailsOverview.tsx": { "no-nested-ternary": { - "count": 8 + "count": 5 }, "no-restricted-imports": { - "count": 2 + "count": 1 } }, "src/app/(dashboard)/guardrails/_components/GuardrailTestPanel.tsx": { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails-monitor/_components/GuardrailsOverview.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails-monitor/_components/GuardrailsOverview.tsx index 9d57f36f93f..8d45b4a4ee8 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails-monitor/_components/GuardrailsOverview.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails-monitor/_components/GuardrailsOverview.tsx @@ -1,8 +1,9 @@ import { DownloadOutlined, RiseOutlined, SafetyOutlined, SettingOutlined, WarningOutlined } from "@ant-design/icons"; import { useQuery } from "@tanstack/react-query"; -import { Button, Card, Col, Row, Spin, Table, Typography } from "antd"; -import type { ColumnsType } from "antd/es/table"; +import type { ColumnDef, OnChangeFn, SortingState } from "@tanstack/react-table"; +import { Button, Col, Row, Spin, Typography } from "antd"; import React, { useMemo, useState } from "react"; +import { DataTable, DataTableSortHeader } from "@/components/shared/DataTable"; import { getGuardrailsUsageOverview } from "@/components/networking"; import { type PerformanceRow } from "@/components/GuardrailsMonitor/mockData"; import { EvaluationSettingsModal } from "./EvaluationSettingsModal"; @@ -82,99 +83,112 @@ export function GuardrailsOverview({ const isLoading = guardrailsLoading; const error = guardrailsError; - const columns: ColumnsType = [ + const columns: ColumnDef[] = [ { - title: "Guardrail", - dataIndex: "name", - key: "name", - render: (name: string, row) => ( + header: "Guardrail", + accessorKey: "name", + enableSorting: false, + cell: ({ row }) => ( ), }, { - title: "Provider", - dataIndex: "provider", - key: "provider", - render: (provider: string) => ( + header: "Provider", + accessorKey: "provider", + enableSorting: false, + cell: ({ row }) => ( - {provider} + {row.original.provider} ), }, { - title: "Requests", - dataIndex: "requestsEvaluated", - key: "requestsEvaluated", - align: "right", - sorter: true, - sortOrder: sortBy === "requestsEvaluated" ? (sortDir === "desc" ? "descend" : "ascend") : null, - render: (v: number) => v.toLocaleString(), + header: ({ column }) => , + accessorKey: "requestsEvaluated", + meta: { numeric: true }, + sortDescFirst: false, + cell: ({ row }) => row.original.requestsEvaluated.toLocaleString(), }, { - title: "Fail Rate", - dataIndex: "failRate", - key: "failRate", - align: "right", - sorter: true, - sortOrder: sortBy === "failRate" ? (sortDir === "desc" ? "descend" : "ascend") : null, - render: (v: number, row) => ( - 15 ? "text-red-600" : v > 5 ? "text-amber-600" : "text-green-600"}> - {v}%{row.trend === "up" && ↑} - {row.trend === "down" && ↓} - - ), - }, - { - title: "Avg. latency added", - dataIndex: "avgLatency", - key: "avgLatency", - align: "right", - sorter: true, - sortOrder: sortBy === "avgLatency" ? (sortDir === "desc" ? "descend" : "ascend") : null, - render: (v?: number) => ( + header: ({ column }) => , + accessorKey: "failRate", + meta: { numeric: true }, + sortDescFirst: false, + cell: ({ row }) => ( 150 ? "text-red-600" : v > 50 ? "text-amber-600" : "text-green-600" + row.original.failRate > 15 + ? "text-red-600" + : row.original.failRate > 5 + ? "text-amber-600" + : "text-green-600" } > - {v != null ? `${v}ms` : "—"} + {row.original.failRate}%{row.original.trend === "up" && ↑} + {row.original.trend === "down" && ↓} ), }, { - title: "Status", - dataIndex: "status", - key: "status", - align: "center", - render: (status: string) => ( + header: ({ column }) => , + accessorKey: "avgLatency", + meta: { numeric: true }, + sortDescFirst: false, + cell: ({ row }) => ( + 150 + ? "text-red-600" + : row.original.avgLatency > 50 + ? "text-amber-600" + : "text-green-600" + } + > + {row.original.avgLatency != null ? `${row.original.avgLatency}ms` : "—"} + + ), + }, + { + header: "Status", + accessorKey: "status", + enableSorting: false, + cell: ({ row }) => ( - {status} + {row.original.status} ), }, ]; const sortableKeys: SortKey[] = ["failRate", "requestsEvaluated", "avgLatency"]; - const handleTableChange = (_pagination: unknown, _filters: unknown, sorter: unknown) => { - const s = sorter as { field?: keyof PerformanceRow; order?: string }; - if (s?.field && sortableKeys.includes(s.field as SortKey)) { - setSortBy(s.field as SortKey); - setSortDir(s.order === "ascend" ? "asc" : "desc"); + const sorting = useMemo(() => [{ id: sortBy, desc: sortDir === "desc" }], [sortBy, sortDir]); + const handleSortingChange: OnChangeFn = (updater) => { + const nextSorting = typeof updater === "function" ? updater(sorting) : updater; + const primarySort = nextSorting[0]; + if (primarySort && sortableKeys.includes(primarySort.id as SortKey)) { + setSortBy(primarySort.id as SortKey); + setSortDir(primarySort.desc ? "desc" : "asc"); } }; @@ -233,43 +247,48 @@ export function GuardrailsOverview({ - +
{(isLoading || error) && ( -
+
{isLoading && } {error && Failed to load data. Try again.}
)} -
-
- - Guardrail Performance - -

Click a guardrail to view details, logs, and configuration

-
-
-
-
- ({ - onClick: () => onSelectGuardrail(row.id), - style: { cursor: "pointer" }, - })} + data={sorted} + getRowId={(row) => row.id} + isLoading={isLoading} + noDataMessage="No data for this period" + onRowClick={(row) => onSelectGuardrail(row.id)} + rowClassName={() => "cursor-pointer"} + sortingMode="server" + sorting={sorting} + onSortingChange={handleSortingChange} + enableSortingRemoval={false} + size="compact" + toolbar={() => ( +
+
+ + Guardrail Performance + +

+ Click a guardrail to view details, logs, and configuration +

+
+
+
+
+ )} /> - +