From 2b93fd775d2878de0aec300a417d3b7215d0731b Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 10 Jan 2026 15:05:30 -0800 Subject: [PATCH] temp commit for branch switching --- .../organizations/OrganizationFilters.tsx | 120 ++++++++++++++++++ .../src/components/networking.tsx | 21 ++- .../src/components/organizations.tsx | 67 +++++++++- 3 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 ui/litellm-dashboard/src/app/(dashboard)/organizations/OrganizationFilters.tsx diff --git a/ui/litellm-dashboard/src/app/(dashboard)/organizations/OrganizationFilters.tsx b/ui/litellm-dashboard/src/app/(dashboard)/organizations/OrganizationFilters.tsx new file mode 100644 index 00000000000..9b3fa2fc026 --- /dev/null +++ b/ui/litellm-dashboard/src/app/(dashboard)/organizations/OrganizationFilters.tsx @@ -0,0 +1,120 @@ +import React from "react"; + +interface OrganizationFiltersProps { + filters: FilterState; + showFilters: boolean; + onToggleFilters: (toggle: boolean) => void; + onChange: (key: K, value: FilterState[K]) => void; + onReset: () => void; +} + +type FilterState = { + org_id: string; + org_alias: string; + sort_by: string; + sort_order: "asc" | "desc"; +}; + +const OrganizationFilters = ({ + filters, + showFilters, + onToggleFilters, + onChange, + onReset, +}: OrganizationFiltersProps) => { + return ( +
+ {/* Search and Filter Controls */} +
+ {/* Organization Alias Search */} +
+ onChange("org_alias", e.target.value)} + /> + + + +
+ + {/* Filter Button */} + + + {/* Reset Filters Button */} + +
+ + {/* Additional Filters */} + {showFilters && ( +
+ {/* Organization ID Search */} +
+ onChange("org_id", e.target.value)} + /> + + + +
+
+ )} +
+ ); +}; + +export default OrganizationFilters; +export type { FilterState }; diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 6fd828dfc25..0a378eba3b2 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -1411,12 +1411,31 @@ export const availableTeamListCall = async (accessToken: string) => { } }; -export const organizationListCall = async (accessToken: string) => { +export const organizationListCall = async ( + accessToken: string, + org_id: string | null = null, + org_alias: string | null = null, +) => { /** * Get all organizations on proxy */ try { let url = proxyBaseUrl ? `${proxyBaseUrl}/organization/list` : `/organization/list`; + const queryParams = new URLSearchParams(); + + if (org_id) { + queryParams.append("org_id", org_id.toString()); + } + + if (org_alias) { + queryParams.append("org_alias", org_alias.toString()); + } + + const queryString = queryParams.toString(); + if (queryString) { + url += `?${queryString}`; + } + const response = await fetch(url, { method: "GET", headers: { diff --git a/ui/litellm-dashboard/src/components/organizations.tsx b/ui/litellm-dashboard/src/components/organizations.tsx index 32ba210161b..d75f3c84a3d 100644 --- a/ui/litellm-dashboard/src/components/organizations.tsx +++ b/ui/litellm-dashboard/src/components/organizations.tsx @@ -34,6 +34,7 @@ import { formatNumberWithCommas } from "../utils/dataUtils"; import NotificationsManager from "./molecules/notifications_manager"; import DeleteResourceModal from "./common_components/DeleteResourceModal"; import TableIconActionButton from "./common_components/IconActionButton/TableIconActionButtons/TableIconActionButton"; +import OrganizationFilters, { FilterState } from "@/app/(dashboard)/organizations/OrganizationFilters"; interface OrganizationsTableProps { organizations: Organization[]; @@ -51,8 +52,10 @@ interface OrganizationsTableProps { export const fetchOrganizations = async ( accessToken: string, setOrganizations: (organizations: Organization[]) => void, + org_id: string | null = null, + org_alias: string | null = null, ) => { - const organizations = await organizationListCall(accessToken); + const organizations = await organizationListCall(accessToken, org_id, org_alias); setOrganizations(organizations); }; @@ -76,12 +79,51 @@ const OrganizationsTable: React.FC = ({ const [isOrgModalVisible, setIsOrgModalVisible] = useState(false); const [form] = Form.useForm(); const [expandedAccordions, setExpandedAccordions] = useState>({}); + const [showFilters, setShowFilters] = useState(false); + const [filters, setFilters] = useState({ + org_id: "", + org_alias: "", + sort_by: "created_at", + sort_order: "desc", + }); - useEffect(() => { + const handleFilterChange = (key: keyof FilterState, value: string) => { + const newFilters = { ...filters, [key]: value }; + setFilters(newFilters); + // Call organizationListCall with the new filters if (accessToken) { - fetchOrganizations(accessToken, setOrganizations); + organizationListCall(accessToken, newFilters.org_id || null, newFilters.org_alias || null) + .then((response) => { + if (response) { + setOrganizations(response); + } + }) + .catch((error) => { + console.error("Error fetching organizations:", error); + }); } - }, [accessToken]); + }; + + const handleFilterReset = () => { + setFilters({ + org_id: "", + org_alias: "", + sort_by: "created_at", + sort_order: "desc", + }); + // Reset organizations list + if (accessToken) { + organizationListCall(accessToken, null, null) + .then((response) => { + if (response) { + setOrganizations(response); + } + }) + .catch((error) => { + console.error("Error fetching organizations:", error); + }); + } + }; const handleDelete = (orgId: string | null) => { if (!orgId) return; @@ -101,7 +143,7 @@ const OrganizationsTable: React.FC = ({ setIsDeleteModalOpen(false); setOrgToDelete(null); // Refresh organizations list - await fetchOrganizations(accessToken, setOrganizations); + await fetchOrganizations(accessToken, setOrganizations, filters.org_id || null, filters.org_alias || null); } catch (error) { console.error("Error deleting organization:", error); } finally { @@ -148,7 +190,7 @@ const OrganizationsTable: React.FC = ({ setIsOrgModalVisible(false); form.resetFields(); // Refresh organizations list - fetchOrganizations(accessToken, setOrganizations); + fetchOrganizations(accessToken, setOrganizations, filters.org_id || null, filters.org_alias || null); } catch (error) { console.error("Error creating organization:", error); } @@ -217,7 +259,18 @@ const OrganizationsTable: React.FC = ({ Click on “Organization ID” to view organization details. - + +
+
+ +
+