From 30fb400cbd9a1317107680949921a5e58b5ce863 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 12 Aug 2026 16:08:22 -0700 Subject: [PATCH] refactor(ui): migrate guardrails content tables to shared DataTable --- .../content_filter/CategoryTable.tsx | 76 ++++++++++--------- .../ContentCategoryConfiguration.tsx | 55 +++++++------- .../content_filter/KeywordTable.tsx | 43 +++++------ .../content_filter/PatternTable.tsx | 62 +++++++-------- 4 files changed, 119 insertions(+), 117 deletions(-) diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/CategoryTable.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/CategoryTable.tsx index cffb634e3d2..cdc85bf0c0f 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/CategoryTable.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/CategoryTable.tsx @@ -1,6 +1,8 @@ import React from "react"; -import { Typography, Select, Table, Tag, Button } from "antd"; +import { Typography, Select, Tag, Button } from "antd"; import { DeleteOutlined } from "@ant-design/icons"; +import type { ColumnDef } from "@tanstack/react-table"; +import { DataTable } from "@/components/shared/DataTable"; const { Text } = Typography; const { Option } = Select; @@ -28,30 +30,32 @@ const CategoryTable: React.FC = ({ onRemove, readOnly = false, }) => { - const columns = [ + const columns: ColumnDef[] = [ { - title: "Category", - dataIndex: "display_name", - key: "display_name", - render: (displayName: string, record: ContentCategory) => ( -
- {displayName} - {displayName !== record.category && ( -
- - {record.category} - -
- )} -
- ), + header: "Category", + accessorKey: "display_name", + cell: ({ row }) => { + const { category, display_name: displayName } = row.original; + return ( +
+ {displayName} + {displayName !== category && ( +
+ + {category} + +
+ )} +
+ ); + }, }, { - title: "Severity Threshold", - dataIndex: "severity_threshold", - key: "severity_threshold", - width: 180, - render: (severity: string, record: ContentCategory) => { + header: "Severity Threshold", + accessorKey: "severity_threshold", + size: 180, + cell: ({ row }) => { + const { id, severity_threshold: severity } = row.original; if (readOnly) { const colorMap = { high: "red", @@ -63,7 +67,7 @@ const CategoryTable: React.FC = ({ return ( onActionChange?.(record.id, value as "BLOCK" | "MASK")} + onChange={(value) => onActionChange?.(id, value as "BLOCK" | "MASK")} style={{ width: 120 }} size="small" > @@ -100,22 +104,22 @@ const CategoryTable: React.FC = ({ if (!readOnly) { columns.push({ - title: "", - key: "actions", - width: 100, - render: (_: any, record: ContentCategory) => ( - ), - } as any); + }); } if (categories.length === 0) { return
No categories configured.
; } - return ; + return row.id} size="compact" />; }; export default CategoryTable; diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/ContentCategoryConfiguration.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/ContentCategoryConfiguration.tsx index 713694f98e7..d0e0a4c6c8b 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/ContentCategoryConfiguration.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/ContentCategoryConfiguration.tsx @@ -1,7 +1,9 @@ import React from "react"; -import { Card, Typography, Select, Table, Tag, Collapse, Button } from "antd"; +import { Card, Typography, Select, Tag, Collapse, Button } from "antd"; import { DeleteOutlined, PlusOutlined, FileTextOutlined } from "@ant-design/icons"; +import type { ColumnDef } from "@tanstack/react-table"; import { getCategoryYaml } from "@/components/networking"; +import { DataTable } from "@/components/shared/DataTable"; const { Title, Text } = Typography; const { Option } = Select; @@ -160,16 +162,15 @@ const ContentCategoryConfiguration: React.FC // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedCategoryName, accessToken]); - const columns = [ + const columns: ColumnDef[] = [ { - title: "Category", - dataIndex: "display_name", - key: "display_name", - render: (text: string, record: SelectedCategory) => { - const category = availableCategories.find((c) => c.name === record.category); + header: "Category", + accessorKey: "display_name", + cell: ({ row }) => { + const category = availableCategories.find((c) => c.name === row.original.category); return (
-
{text}
+
{row.original.display_name}
{category?.description && (
{category.description}
)} @@ -178,14 +179,13 @@ const ContentCategoryConfiguration: React.FC }, }, { - title: "Action", - dataIndex: "action", - key: "action", - width: 150, - render: (action: string, record: SelectedCategory) => ( + header: "Action", + accessorKey: "action", + size: 150, + cell: ({ row }) => ( onCategoryUpdate(record.id, "severity_threshold", value)} + value={row.original.severity_threshold} + onChange={(value) => onCategoryUpdate(row.original.id, "severity_threshold", value)} style={{ width: "100%" }} > @@ -215,11 +214,11 @@ const ContentCategoryConfiguration: React.FC ), }, { - title: "", - key: "actions", - width: 80, - render: (_: any, record: SelectedCategory) => ( - ), @@ -322,7 +321,7 @@ const ContentCategoryConfiguration: React.FC {selectedCategories.length > 0 ? ( <> -
+ row.id} size="compact" />
= ({ keywords, onActionChange, onRemove }) => { - const columns = [ + const columns: ColumnDef[] = [ { - title: "Keyword", - dataIndex: "keyword", - key: "keyword", + header: "Keyword", + accessorKey: "keyword", }, { - title: "Action", - dataIndex: "action", - key: "action", - width: 150, - render: (action: string, record: BlockedWord) => ( + header: "Action", + accessorKey: "action", + size: 150, + cell: ({ row }) => (
; + return row.id} size="compact" />; }; export default KeywordTable; diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/PatternTable.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/PatternTable.tsx index bf5b75b52fb..403dbec25cc 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/PatternTable.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/PatternTable.tsx @@ -1,6 +1,8 @@ import React from "react"; -import { Typography, Select, Table, Tag, Button } from "antd"; +import { Typography, Select, Tag, Button } from "antd"; import { DeleteOutlined } from "@ant-design/icons"; +import type { ColumnDef } from "@tanstack/react-table"; +import { DataTable } from "@/components/shared/DataTable"; const { Text } = Typography; const { Option } = Select; @@ -21,44 +23,42 @@ interface PatternTableProps { } const PatternTable: React.FC = ({ patterns, onActionChange, onRemove }) => { - const columns = [ + const columns: ColumnDef[] = [ { - title: "Type", - dataIndex: "type", - key: "type", - width: 100, - render: (type: string) => ( - {type === "prebuilt" ? "Prebuilt" : "Custom"} + header: "Type", + accessorKey: "type", + size: 100, + cell: ({ row }) => ( + + {row.original.type === "prebuilt" ? "Prebuilt" : "Custom"} + ), }, { - title: "Pattern name", - dataIndex: "name", - key: "name", - render: (_: string, record: Pattern) => record.display_name || record.name, + header: "Pattern name", + accessorKey: "name", + cell: ({ row }) => row.original.display_name || row.original.name, }, { - title: "Regex pattern", - dataIndex: "pattern", - key: "pattern", - render: (pattern: string) => - pattern ? ( + header: "Regex pattern", + accessorKey: "pattern", + cell: ({ row }) => + row.original.pattern ? ( - {pattern.substring(0, 40)}... + {row.original.pattern.substring(0, 40)}... ) : ( "-" ), }, { - title: "Action", - dataIndex: "action", - key: "action", - width: 150, - render: (action: string, record: Pattern) => ( + header: "Action", + accessorKey: "action", + size: 150, + cell: ({ row }) => (
; + return row.id} size="compact" />; }; export default PatternTable;