mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): migrate permissions views + DeletedKeys/Teams pages
- VectorStorePermissions / AgentPermissions: @tremor Text/Badge + @heroicons Database/UserGroup + antd Tooltip \u2192 shadcn Badge + Tooltip + lucide Database/Users. Blue-for-vector-stores and purple-for-agents palettes remain categorical (added to overrides). - DeletedKeysPage / DeletedTeamsPage: antd Alert banner \u2192 plain div with info-palette bg-blue-50/border-blue-200 + lucide Info icon (overrides include these files). Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
parent
e00efbf810
commit
1fe796cebe
5 changed files with 100 additions and 64 deletions
|
|
@ -49,7 +49,11 @@
|
|||
"src/components/common_components/DeleteResourceModal.tsx",
|
||||
"src/components/common_components/PremiumLoggingSettings.tsx",
|
||||
"src/components/common_components/AutoRotationView.tsx",
|
||||
"src/components/agents/agent_card.tsx"
|
||||
"src/components/agents/agent_card.tsx",
|
||||
"src/components/permissions/VectorStorePermissions.tsx",
|
||||
"src/components/permissions/AgentPermissions.tsx",
|
||||
"src/components/DeletedKeysPage/DeletedKeysPage.tsx",
|
||||
"src/components/DeletedTeamsPage/DeletedTeamsPage.tsx"
|
||||
],
|
||||
"rules": {
|
||||
"litellm-ui/no-banned-ui-imports": "off",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
import { useState } from "react";
|
||||
import { Alert } from "antd";
|
||||
import { Info } from "lucide-react";
|
||||
import { useDeletedKeys } from "@/app/(dashboard)/hooks/keys/useKeys";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
import { DeletedKeysTable } from "./DeletedKeysTable/DeletedKeysTable";
|
||||
|
|
@ -19,13 +19,16 @@ export default function DeletedKeysPage() {
|
|||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{!premiumUser && (
|
||||
<Alert
|
||||
type="info"
|
||||
banner
|
||||
showIcon
|
||||
message="Coming soon to Enterprise"
|
||||
description="Deleted key auditing is graduating from beta into our Enterprise audit & compliance suite."
|
||||
/>
|
||||
<div className="flex gap-2 items-start p-3 rounded-md bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-900 text-blue-800 dark:text-blue-200">
|
||||
<Info className="h-4 w-4 mt-0.5 shrink-0" />
|
||||
<div>
|
||||
<div className="font-semibold">Coming soon to Enterprise</div>
|
||||
<div className="text-sm">
|
||||
Deleted key auditing is graduating from beta into our Enterprise
|
||||
audit & compliance suite.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<DeletedKeysTable
|
||||
keys={keysData?.keys || []}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"use client";
|
||||
import { Alert } from "antd";
|
||||
import { Info } from "lucide-react";
|
||||
import { useDeletedTeams } from "@/app/(dashboard)/hooks/teams/useTeams";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
import { DeletedTeamsTable } from "./DeletedTeamsTable/DeletedTeamsTable";
|
||||
|
|
@ -15,13 +15,16 @@ export default function DeletedTeamsPage() {
|
|||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{!premiumUser && (
|
||||
<Alert
|
||||
type="info"
|
||||
banner
|
||||
showIcon
|
||||
message="Coming soon to Enterprise"
|
||||
description="Deleted team auditing is graduating from beta into our Enterprise audit & compliance suite."
|
||||
/>
|
||||
<div className="flex gap-2 items-start p-3 rounded-md bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-900 text-blue-800 dark:text-blue-200">
|
||||
<Info className="h-4 w-4 mt-0.5 shrink-0" />
|
||||
<div>
|
||||
<div className="font-semibold">Coming soon to Enterprise</div>
|
||||
<div className="text-sm">
|
||||
Deleted team auditing is graduating from beta into our Enterprise
|
||||
audit & compliance suite.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<DeletedTeamsTable
|
||||
teams={teamsData || []}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Text, Badge } from "@tremor/react";
|
||||
import { UserGroupIcon } from "@heroicons/react/outline";
|
||||
import { Tooltip } from "antd";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { Users } from "lucide-react";
|
||||
import { getAgentsList } from "../networking";
|
||||
|
||||
interface Agent {
|
||||
agent_id: string;
|
||||
agent_name: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
agent_config?: Record<string, any>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
agent_card_params?: Record<string, any>;
|
||||
}
|
||||
|
||||
|
|
@ -17,14 +24,13 @@ interface AgentPermissionsProps {
|
|||
accessToken?: string | null;
|
||||
}
|
||||
|
||||
export function AgentPermissions({
|
||||
agents,
|
||||
agentAccessGroups = [],
|
||||
accessToken
|
||||
export function AgentPermissions({
|
||||
agents,
|
||||
agentAccessGroups = [],
|
||||
accessToken,
|
||||
}: AgentPermissionsProps) {
|
||||
const [agentDetails, setAgentDetails] = useState<Agent[]>([]);
|
||||
|
||||
// Fetch agent details when component mounts
|
||||
useEffect(() => {
|
||||
const fetchAgentDetails = async () => {
|
||||
if (accessToken && agents.length > 0) {
|
||||
|
|
@ -41,53 +47,64 @@ export function AgentPermissions({
|
|||
fetchAgentDetails();
|
||||
}, [accessToken, agents.length]);
|
||||
|
||||
// Function to get display name for agent
|
||||
const getAgentDisplayName = (agentId: string) => {
|
||||
const agentDetail = agentDetails.find((agent) => agent.agent_id === agentId);
|
||||
const agentDetail = agentDetails.find((a) => a.agent_id === agentId);
|
||||
if (agentDetail) {
|
||||
const truncatedId = agentId.length > 7 ? `${agentId.slice(0, 3)}...${agentId.slice(-4)}` : agentId;
|
||||
const truncatedId =
|
||||
agentId.length > 7
|
||||
? `${agentId.slice(0, 3)}...${agentId.slice(-4)}`
|
||||
: agentId;
|
||||
return `${agentDetail.agent_name} (${truncatedId})`;
|
||||
}
|
||||
return agentId;
|
||||
};
|
||||
|
||||
// Merge agents and access groups into one list
|
||||
const mergedItems = [
|
||||
...agents.map((agent) => ({ type: "agent", value: agent })),
|
||||
...agentAccessGroups.map((group) => ({ type: "accessGroup", value: group })),
|
||||
...agentAccessGroups.map((group) => ({
|
||||
type: "accessGroup",
|
||||
value: group,
|
||||
})),
|
||||
];
|
||||
const totalCount = mergedItems.length;
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<UserGroupIcon className="h-4 w-4 text-purple-600" />
|
||||
<Text className="font-semibold text-gray-900">Agents</Text>
|
||||
<Badge color="purple" size="xs">
|
||||
<Users className="h-4 w-4 text-purple-600 dark:text-purple-400" />
|
||||
<span className="font-semibold text-foreground">Agents</span>
|
||||
<Badge className="bg-purple-100 text-purple-700 dark:bg-purple-950 dark:text-purple-300 text-xs">
|
||||
{totalCount}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
|
||||
{totalCount > 0 ? (
|
||||
<div className="max-h-[400px] overflow-y-auto space-y-2 pr-1">
|
||||
{mergedItems.map((item, index) => (
|
||||
<div key={index} className="space-y-2">
|
||||
<div
|
||||
className="flex items-center gap-3 py-2 px-3 rounded-lg border border-gray-200 bg-white"
|
||||
>
|
||||
<div className="flex items-center gap-3 py-2 px-3 rounded-lg border border-border bg-background">
|
||||
<div className="flex items-center gap-2 flex-1 min-w-0">
|
||||
{item.type === "agent" ? (
|
||||
<Tooltip title={`Full ID: ${item.value}`} placement="top">
|
||||
<div className="inline-flex items-center gap-2 min-w-0">
|
||||
<span className="inline-block w-1.5 h-1.5 bg-purple-500 rounded-full flex-shrink-0"></span>
|
||||
<span className="text-sm font-medium text-gray-900 truncate">{getAgentDisplayName(item.value)}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="inline-flex items-center gap-2 min-w-0">
|
||||
<span className="inline-block w-1.5 h-1.5 bg-purple-500 rounded-full flex-shrink-0" />
|
||||
<span className="text-sm font-medium text-foreground truncate">
|
||||
{getAgentDisplayName(item.value)}
|
||||
</span>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Full ID: {item.value}</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
) : (
|
||||
<div className="inline-flex items-center gap-2 min-w-0">
|
||||
<span className="inline-block w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"></span>
|
||||
<span className="text-sm font-medium text-gray-900 truncate">{item.value}</span>
|
||||
<span className="ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-green-600 bg-green-50 border border-green-200 rounded uppercase tracking-wide flex-shrink-0">
|
||||
<span className="inline-block w-1.5 h-1.5 bg-emerald-500 rounded-full flex-shrink-0" />
|
||||
<span className="text-sm font-medium text-foreground truncate">
|
||||
{item.value}
|
||||
</span>
|
||||
<span className="ml-1 px-1.5 py-0.5 text-[9px] font-semibold text-emerald-600 bg-emerald-50 border border-emerald-200 dark:bg-emerald-950/30 dark:border-emerald-900 dark:text-emerald-300 rounded uppercase tracking-wide flex-shrink-0">
|
||||
Group
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -98,9 +115,11 @@ export function AgentPermissions({
|
|||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200">
|
||||
<UserGroupIcon className="h-4 w-4 text-gray-400" />
|
||||
<Text className="text-gray-500 text-sm">No agents or access groups configured</Text>
|
||||
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-muted border border-border">
|
||||
<Users className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="text-muted-foreground text-sm">
|
||||
No agents or access groups configured
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -108,4 +127,3 @@ export function AgentPermissions({
|
|||
}
|
||||
|
||||
export default AgentPermissions;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Text, Badge } from "@tremor/react";
|
||||
import { DatabaseIcon } from "@heroicons/react/outline";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Database } from "lucide-react";
|
||||
import { vectorStoreListCall } from "../networking";
|
||||
|
||||
interface VectorStoreDetails {
|
||||
|
|
@ -13,10 +13,14 @@ interface VectorStorePermissionsProps {
|
|||
accessToken?: string | null;
|
||||
}
|
||||
|
||||
export function VectorStorePermissions({ vectorStores, accessToken }: VectorStorePermissionsProps) {
|
||||
const [vectorStoreDetails, setVectorStoreDetails] = useState<VectorStoreDetails[]>([]);
|
||||
export function VectorStorePermissions({
|
||||
vectorStores,
|
||||
accessToken,
|
||||
}: VectorStorePermissionsProps) {
|
||||
const [vectorStoreDetails, setVectorStoreDetails] = useState<
|
||||
VectorStoreDetails[]
|
||||
>([]);
|
||||
|
||||
// Fetch vector store details when component mounts
|
||||
useEffect(() => {
|
||||
const fetchVectorStores = async () => {
|
||||
if (!accessToken || vectorStores.length === 0) return;
|
||||
|
|
@ -25,6 +29,7 @@ export function VectorStorePermissions({ vectorStores, accessToken }: VectorStor
|
|||
const response = await vectorStoreListCall(accessToken);
|
||||
if (response.data) {
|
||||
setVectorStoreDetails(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
response.data.map((store: any) => ({
|
||||
vector_store_id: store.vector_store_id,
|
||||
vector_store_name: store.vector_store_name,
|
||||
|
|
@ -39,9 +44,10 @@ export function VectorStorePermissions({ vectorStores, accessToken }: VectorStor
|
|||
fetchVectorStores();
|
||||
}, [accessToken, vectorStores.length]);
|
||||
|
||||
// Function to get display name for vector store
|
||||
const getVectorStoreDisplayName = (storeId: string) => {
|
||||
const storeDetail = vectorStoreDetails.find((store) => store.vector_store_id === storeId);
|
||||
const storeDetail = vectorStoreDetails.find(
|
||||
(store) => store.vector_store_id === storeId,
|
||||
);
|
||||
if (storeDetail) {
|
||||
return `${storeDetail.vector_store_name || storeDetail.vector_store_id} (${storeDetail.vector_store_id})`;
|
||||
}
|
||||
|
|
@ -51,9 +57,9 @@ export function VectorStorePermissions({ vectorStores, accessToken }: VectorStor
|
|||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<DatabaseIcon className="h-4 w-4 text-blue-600" />
|
||||
<Text className="font-semibold text-gray-900">Vector Stores</Text>
|
||||
<Badge color="blue" size="xs">
|
||||
<Database className="h-4 w-4 text-blue-600 dark:text-blue-400" />
|
||||
<span className="font-semibold text-foreground">Vector Stores</span>
|
||||
<Badge className="bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-300 text-xs">
|
||||
{vectorStores.length}
|
||||
</Badge>
|
||||
</div>
|
||||
|
|
@ -63,16 +69,18 @@ export function VectorStorePermissions({ vectorStores, accessToken }: VectorStor
|
|||
{vectorStores.map((store, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-50 border border-blue-200 text-blue-800 text-sm font-medium"
|
||||
className="inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-900 text-blue-800 dark:text-blue-200 text-sm font-medium"
|
||||
>
|
||||
{getVectorStoreDisplayName(store)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-gray-50 border border-gray-200">
|
||||
<DatabaseIcon className="h-4 w-4 text-gray-400" />
|
||||
<Text className="text-gray-500 text-sm">No vector stores configured</Text>
|
||||
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-muted border border-border">
|
||||
<Database className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="text-muted-foreground text-sm">
|
||||
No vector stores configured
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue