diff --git a/ui/litellm-dashboard/src/components/KeyAliasSelect/PaginatedKeyAliasSelect/PaginatedKeyAliasSelect.tsx b/ui/litellm-dashboard/src/components/KeyAliasSelect/PaginatedKeyAliasSelect/PaginatedKeyAliasSelect.tsx index 940f0b7e951..aedccea6f16 100644 --- a/ui/litellm-dashboard/src/components/KeyAliasSelect/PaginatedKeyAliasSelect/PaginatedKeyAliasSelect.tsx +++ b/ui/litellm-dashboard/src/components/KeyAliasSelect/PaginatedKeyAliasSelect/PaginatedKeyAliasSelect.tsx @@ -1,8 +1,15 @@ import { useInfiniteKeyAliases } from "@/app/(dashboard)/hooks/keys/useKeyAliases"; -import { LoadingOutlined } from "@ant-design/icons"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { cn } from "@/lib/utils"; import { useDebouncedState } from "@tanstack/react-pacer/debouncer"; -import { Select } from "antd"; -import { useMemo, useState, type UIEvent } from "react"; +import { ChevronsUpDown, Loader2, X } from "lucide-react"; +import { useMemo, useRef, useState } from "react"; export interface PaginatedKeyAliasSelectProps { value?: string; @@ -28,39 +35,36 @@ export const PaginatedKeyAliasSelect = ({ disabled = false, allFilters, }: PaginatedKeyAliasSelectProps) => { + const [open, setOpen] = useState(false); const [searchInput, setSearchInput] = useState(""); const [debouncedSearch, setDebouncedSearch] = useDebouncedState("", { wait: DEBOUNCE_MS, }); + const listRef = useRef(null); const teamId = allFilters?.["Team ID"] || undefined; - const { - data, - fetchNextPage, - hasNextPage, - isFetchingNextPage, - isLoading, - } = useInfiniteKeyAliases(pageSize, debouncedSearch || undefined, teamId); + const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = + useInfiniteKeyAliases(pageSize, debouncedSearch || undefined, teamId); const options = useMemo(() => { if (!data?.pages) return []; const seen = new Set(); - const result: { label: string; value: string }[] = []; + const result: string[] = []; for (const page of data.pages) { for (const alias of page.aliases) { if (!alias || seen.has(alias)) continue; seen.add(alias); - result.push({ label: alias, value: alias }); + result.push(alias); } } return result; }, [data]); - const handlePopupScroll = (e: UIEvent) => { + const handleScroll = (e: React.UIEvent) => { const target = e.currentTarget; const scrollRatio = (target.scrollTop + target.clientHeight) / target.scrollHeight; @@ -70,41 +74,101 @@ export const PaginatedKeyAliasSelect = ({ } }; - const handleSearch = (value: string) => { - setSearchInput(value); - setDebouncedSearch(value); + const handleSearch = (v: string) => { + setSearchInput(v); + setDebouncedSearch(v); }; - const handleChange = (v: string | null) => { - onChange?.(v ?? ""); + const select = (alias: string) => { + onChange?.(alias); + setOpen(false); + }; + + const clear = (e: React.MouseEvent) => { + e.stopPropagation(); + onChange?.(""); }; return ( - handleSearch(e.target.value)} + className="h-8" + /> + +
+ {isLoading && options.length === 0 ? ( +
+ +
+ ) : options.length === 0 ? ( +
+ No key aliases found +
+ ) : ( + options.map((alias) => ( + + )) + )} {isFetchingNextPage && ( -
- +
+
)} - - )} - /> +
+ + ); }; diff --git a/ui/litellm-dashboard/src/components/common_components/chartUtils.tsx b/ui/litellm-dashboard/src/components/common_components/chartUtils.tsx index c0930f290f6..7567a14a454 100644 --- a/ui/litellm-dashboard/src/components/common_components/chartUtils.tsx +++ b/ui/litellm-dashboard/src/components/common_components/chartUtils.tsx @@ -1,3 +1,4 @@ +// eslint-disable-next-line litellm-ui/no-banned-ui-imports import type { CustomTooltipProps } from "@tremor/react"; import { SpendMetrics } from "../UsagePage/types";