setSelectedPolicyId(null)}
+ onEdit={(policy) => {
+ setEditingPolicy(policy);
+ setIsAddPolicyModalVisible(true);
+ setSelectedPolicyId(null);
+ }}
+ accessToken={accessToken}
+ isAdmin={isAdmin}
+ fetchPolicy={fetchPolicyById}
+ />
+ ) : (
+ <>
+
+ {isAdmin && (
+ }
+ onClick={() => {
+ setEditingPolicy(null);
+ setIsAddPolicyModalVisible(true);
+ }}
+ >
+ Add New Policy
+
+ )}
+
+ {
+ setEditingPolicy(policy);
+ setIsAddPolicyModalVisible(true);
+ }}
+ onViewClick={(policyId) => setSelectedPolicyId(policyId)}
+ isAdmin={isAdmin}
+ />
+ >
+ ),
+ },
+ {
+ key: "attachments",
+ label: "Attachments",
+ children: (
+ <>
+
+ {isAdmin && (
+ }
+ onClick={() => setIsAddAttachmentModalVisible(true)}
+ disabled={policiesList.length === 0}
+ >
+ Add New Attachment
+
+ )}
+
+
+ >
+ ),
+ },
+ ];
+
+ return (
+
+
+
+
{
+ setIsAddPolicyModalVisible(false);
+ setEditingPolicy(null);
+ }}
+ onSuccess={handlePolicySuccess}
+ accessToken={accessToken}
+ editingPolicy={editingPolicy}
+ existingPolicies={policiesList}
+ availableGuardrails={guardrailsList}
+ onCreatePolicy={handleCreatePolicy}
+ onUpdatePolicy={handleUpdatePolicy}
+ />
+
+ setIsAddAttachmentModalVisible(false)}
+ onSuccess={handleAttachmentSuccess}
+ accessToken={accessToken}
+ policies={policiesList}
+ onCreateAttachment={handleCreateAttachment}
+ />
+
+ );
+};
+
+export default PoliciesPanel;
diff --git a/ui/litellm-dashboard/src/components/policies/policy_info.tsx b/ui/litellm-dashboard/src/components/policies/policy_info.tsx
new file mode 100644
index 00000000000..2ee6877093d
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/policies/policy_info.tsx
@@ -0,0 +1,168 @@
+import React, { useState, useEffect } from "react";
+import {
+ Card,
+ Descriptions,
+ Tag,
+ Button,
+ Space,
+ Typography,
+ Spin,
+ Divider,
+} from "antd";
+import { ArrowLeftOutlined, EditOutlined } from "@ant-design/icons";
+import { Policy } from "./types";
+
+const { Title, Text } = Typography;
+
+interface PolicyInfoViewProps {
+ policyId: string;
+ onClose: () => void;
+ onEdit: (policy: Policy) => void;
+ accessToken: string | null;
+ isAdmin: boolean;
+ fetchPolicy: (policyId: string) => Promise;
+}
+
+const PolicyInfoView: React.FC = ({
+ policyId,
+ onClose,
+ onEdit,
+ accessToken,
+ isAdmin,
+ fetchPolicy,
+}) => {
+ const [policy, setPolicy] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ const loadPolicy = async () => {
+ if (!accessToken || !policyId) return;
+
+ setIsLoading(true);
+ try {
+ const data = await fetchPolicy(policyId);
+ setPolicy(data);
+ } catch (error) {
+ console.error("Error fetching policy:", error);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ loadPolicy();
+ }, [policyId, accessToken, fetchPolicy]);
+
+ if (isLoading) {
+ return (
+
+
+
+ );
+ }
+
+ if (!policy) {
+ return (
+
+ Policy not found
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ } onClick={onClose}>
+ Back to Policies
+
+ {isAdmin && (
+ }
+ onClick={() => onEdit(policy)}
+ >
+ Edit Policy
+
+ )}
+
+
+ {policy.policy_name}
+
+
+
+ {policy.policy_id}
+
+
+ {policy.description || No description}
+
+
+ {policy.inherit ? (
+ {policy.inherit}
+ ) : (
+ None
+ )}
+
+
+ {policy.created_at
+ ? new Date(policy.created_at).toLocaleString()
+ : "-"}
+
+
+ {policy.updated_at
+ ? new Date(policy.updated_at).toLocaleString()
+ : "-"}
+
+
+
+ Guardrails Configuration
+
+
+
+
+ {policy.guardrails_add && policy.guardrails_add.length > 0 ? (
+ policy.guardrails_add.map((g) => (
+
+ {g}
+
+ ))
+ ) : (
+ None
+ )}
+
+
+
+
+ {policy.guardrails_remove && policy.guardrails_remove.length > 0 ? (
+ policy.guardrails_remove.map((g) => (
+
+ {g}
+
+ ))
+ ) : (
+ None
+ )}
+
+
+
+
+ Conditions
+
+
+
+ {policy.condition?.model ? (
+ {policy.condition.model}
+ ) : (
+ No model condition (applies to all models)
+ )}
+
+
+
+
+ );
+};
+
+export default PolicyInfoView;
diff --git a/ui/litellm-dashboard/src/components/policies/policy_table.tsx b/ui/litellm-dashboard/src/components/policies/policy_table.tsx
new file mode 100644
index 00000000000..072ad206d27
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/policies/policy_table.tsx
@@ -0,0 +1,160 @@
+import React from "react";
+import { Table, Tag, Button, Space, Tooltip, Typography } from "antd";
+import { DeleteOutlined, EditOutlined, EyeOutlined } from "@ant-design/icons";
+import { Policy } from "./types";
+
+const { Text } = Typography;
+
+interface PolicyTableProps {
+ policies: Policy[];
+ isLoading: boolean;
+ onDeleteClick: (policyId: string, policyName: string) => void;
+ onEditClick: (policy: Policy) => void;
+ onViewClick: (policyId: string) => void;
+ isAdmin: boolean;
+}
+
+const PolicyTable: React.FC = ({
+ policies,
+ isLoading,
+ onDeleteClick,
+ onEditClick,
+ onViewClick,
+ isAdmin,
+}) => {
+ const columns = [
+ {
+ title: "Policy Name",
+ dataIndex: "policy_name",
+ key: "policy_name",
+ render: (text: string, record: Policy) => (
+
+ ),
+ },
+ {
+ title: "Description",
+ dataIndex: "description",
+ key: "description",
+ render: (text: string | null) => text || -,
+ },
+ {
+ title: "Inherits From",
+ dataIndex: "inherit",
+ key: "inherit",
+ render: (text: string | null) =>
+ text ? {text} : -,
+ },
+ {
+ title: "Guardrails (Add)",
+ dataIndex: "guardrails_add",
+ key: "guardrails_add",
+ render: (guardrails: string[]) => (
+
+ {guardrails && guardrails.length > 0 ? (
+ guardrails.slice(0, 3).map((g) => (
+
+ {g}
+
+ ))
+ ) : (
+ -
+ )}
+ {guardrails && guardrails.length > 3 && (
+
+ +{guardrails.length - 3} more
+
+ )}
+
+ ),
+ },
+ {
+ title: "Guardrails (Remove)",
+ dataIndex: "guardrails_remove",
+ key: "guardrails_remove",
+ render: (guardrails: string[]) => (
+
+ {guardrails && guardrails.length > 0 ? (
+ guardrails.slice(0, 3).map((g) => (
+
+ {g}
+
+ ))
+ ) : (
+ -
+ )}
+ {guardrails && guardrails.length > 3 && (
+
+ +{guardrails.length - 3} more
+
+ )}
+
+ ),
+ },
+ {
+ title: "Model Condition",
+ dataIndex: "condition",
+ key: "condition",
+ render: (condition: { model?: string } | null) =>
+ condition?.model ? (
+ {condition.model}
+ ) : (
+ -
+ ),
+ },
+ {
+ title: "Actions",
+ key: "actions",
+ render: (_: any, record: Policy) => (
+
+
+ }
+ onClick={() => onViewClick(record.policy_id)}
+ />
+
+ {isAdmin && (
+ <>
+
+ }
+ onClick={() => onEditClick(record)}
+ />
+
+
+ }
+ onClick={() =>
+ onDeleteClick(record.policy_id, record.policy_name)
+ }
+ />
+
+ >
+ )}
+
+ ),
+ },
+ ];
+
+ return (
+
+ `${range[0]}-${range[1]} of ${total} policies`,
+ }}
+ />
+ );
+};
+
+export default PolicyTable;
diff --git a/ui/litellm-dashboard/src/components/policies/types.ts b/ui/litellm-dashboard/src/components/policies/types.ts
new file mode 100644
index 00000000000..2430180b9db
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/policies/types.ts
@@ -0,0 +1,66 @@
+export interface Policy {
+ policy_id: string;
+ policy_name: string;
+ inherit: string | null;
+ description: string | null;
+ guardrails_add: string[];
+ guardrails_remove: string[];
+ condition: PolicyCondition | null;
+ created_at?: string;
+ updated_at?: string;
+ created_by?: string;
+ updated_by?: string;
+}
+
+export interface PolicyCondition {
+ model?: string;
+}
+
+export interface PolicyAttachment {
+ attachment_id: string;
+ policy_name: string;
+ scope: string | null;
+ teams: string[];
+ keys: string[];
+ models: string[];
+ created_at?: string;
+ updated_at?: string;
+ created_by?: string;
+ updated_by?: string;
+}
+
+export interface PolicyCreateRequest {
+ policy_name: string;
+ inherit?: string;
+ description?: string;
+ guardrails_add?: string[];
+ guardrails_remove?: string[];
+ condition?: PolicyCondition;
+}
+
+export interface PolicyUpdateRequest {
+ policy_name?: string;
+ inherit?: string;
+ description?: string;
+ guardrails_add?: string[];
+ guardrails_remove?: string[];
+ condition?: PolicyCondition;
+}
+
+export interface PolicyAttachmentCreateRequest {
+ policy_name: string;
+ scope?: string;
+ teams?: string[];
+ keys?: string[];
+ models?: string[];
+}
+
+export interface PolicyListResponse {
+ policies: Policy[];
+ total_count: number;
+}
+
+export interface PolicyAttachmentListResponse {
+ attachments: PolicyAttachment[];
+ total_count: number;
+}