mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): TeamsFilters to shadcn
- @tremor Select/SelectItem + raw <input> + inline SVG icons \u2192 shadcn Select/Input/Button + lucide Search/Filter/User/RotateCcw. - Active-filter indicator dot (blue) preserved inline. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
parent
02779b37ec
commit
87234e5be8
1 changed files with 48 additions and 74 deletions
|
|
@ -1,4 +1,14 @@
|
|||
import { Select, SelectItem } from "@tremor/react";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Filter, RotateCcw, Search, User } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import React from "react";
|
||||
import { Organization } from "@/components/networking";
|
||||
|
||||
|
|
@ -7,7 +17,10 @@ interface TeamsFiltersProps {
|
|||
organizations: Organization[] | null;
|
||||
showFilters: boolean;
|
||||
onToggleFilters: (toggle: boolean) => void;
|
||||
onChange: <K extends keyof FilterState>(key: K, value: FilterState[K]) => void;
|
||||
onChange: <K extends keyof FilterState>(
|
||||
key: K,
|
||||
value: FilterState[K],
|
||||
) => void;
|
||||
onReset: () => void;
|
||||
}
|
||||
|
||||
|
|
@ -29,107 +42,68 @@ const TeamsFilters = ({
|
|||
}: TeamsFiltersProps) => {
|
||||
return (
|
||||
<div className="flex flex-col space-y-4">
|
||||
{/* Search and Filter Controls */}
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
{/* Team Alias Search */}
|
||||
<div className="relative w-64">
|
||||
<input
|
||||
type="text"
|
||||
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none" />
|
||||
<Input
|
||||
placeholder="Search by Team Name..."
|
||||
className="w-full px-3 py-2 pl-8 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
className="pl-8"
|
||||
value={filters.team_alias}
|
||||
onChange={(e) => onChange("team_alias", e.target.value)}
|
||||
/>
|
||||
<svg
|
||||
className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Filter Button */}
|
||||
<button
|
||||
className={`px-3 py-2 text-sm border rounded-md hover:bg-gray-50 flex items-center gap-2 ${showFilters ? "bg-gray-100" : ""}`}
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(showFilters && "bg-muted")}
|
||||
onClick={() => onToggleFilters(!showFilters)}
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"
|
||||
/>
|
||||
</svg>
|
||||
<Filter className="h-4 w-4" />
|
||||
Filters
|
||||
{(filters.team_id || filters.team_alias || filters.organization_id) && (
|
||||
<span data-testid="active-filter-indicator" className="w-2 h-2 rounded-full bg-blue-500"></span>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* Reset Filters Button */}
|
||||
<button
|
||||
className="px-3 py-2 text-sm border rounded-md hover:bg-gray-50 flex items-center gap-2"
|
||||
onClick={onReset}
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||
<span
|
||||
data-testid="active-filter-indicator"
|
||||
className="w-2 h-2 rounded-full bg-blue-500"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<Button variant="outline" onClick={onReset}>
|
||||
<RotateCcw className="h-4 w-4" />
|
||||
Reset Filters
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Additional Filters */}
|
||||
{showFilters && (
|
||||
<div className="flex flex-wrap items-center gap-3 mt-3">
|
||||
{/* Team ID Search */}
|
||||
<div className="relative w-64">
|
||||
<input
|
||||
type="text"
|
||||
<User className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none" />
|
||||
<Input
|
||||
placeholder="Enter Team ID"
|
||||
className="w-full px-3 py-2 pl-8 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
className="pl-8"
|
||||
value={filters.team_id}
|
||||
onChange={(e) => onChange("team_id", e.target.value)}
|
||||
/>
|
||||
<svg
|
||||
className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5.121 17.804A13.937 13.937 0 0112 16c2.5 0 4.847.655 6.879 1.804M15 10a3 3 0 11-6 0 3 3 0 016 0zm6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Organization Dropdown */}
|
||||
<div className="w-64">
|
||||
<Select
|
||||
value={filters.organization_id || ""}
|
||||
value={filters.organization_id || undefined}
|
||||
onValueChange={(value) => onChange("organization_id", value)}
|
||||
placeholder="Select Organization"
|
||||
>
|
||||
{organizations?.map((org) => (
|
||||
<SelectItem key={org.organization_id} value={org.organization_id || ""}>
|
||||
{org.organization_alias || org.organization_id}
|
||||
</SelectItem>
|
||||
))}
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select Organization" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{organizations?.map((org) => (
|
||||
<SelectItem
|
||||
key={org.organization_id}
|
||||
value={org.organization_id || ""}
|
||||
>
|
||||
{org.organization_alias || org.organization_id}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue