diff --git a/ui/litellm-dashboard/src/components/ui/badge.tsx b/ui/litellm-dashboard/src/components/ui/badge.tsx index f64de004b52..bf17c76aa55 100644 --- a/ui/litellm-dashboard/src/components/ui/badge.tsx +++ b/ui/litellm-dashboard/src/components/ui/badge.tsx @@ -1,22 +1,21 @@ -"use client"; - import * as React from "react"; -import { type VariantProps } from "cva"; +import { mergeProps } from "@base-ui/react/merge-props"; import { useRender } from "@base-ui/react/use-render"; +import { type VariantProps } from "cva"; import { cn, cva } from "@/lib/cva.config"; const badgeVariants = cva({ - base: "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [&>svg]:pointer-events-none [&>svg]:size-3", + base: "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", variants: { variant: { - default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90", - secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", + secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80", destructive: - "bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90", - outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", - ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground", - link: "text-primary underline-offset-4 [a&]:hover:underline", + "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20", + outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground", + ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50", + link: "text-primary underline-offset-4 hover:underline", }, }, defaultVariants: { @@ -24,22 +23,16 @@ const badgeVariants = cva({ }, }); -type BadgeProps = React.ComponentPropsWithoutRef<"span"> & - VariantProps & { - render?: useRender.RenderProp; - }; +type BadgeProps = useRender.ComponentProps<"span"> & VariantProps; const Badge = React.forwardRef( ({ className, variant = "default", render, ...props }, ref) => useRender({ - render: render ?? , + defaultTagName: "span", ref, - props: { - "data-slot": "badge", - "data-variant": variant, - className: cn(badgeVariants({ variant }), className), - ...props, - }, + props: mergeProps<"span">({ className: cn(badgeVariants({ variant }), className) }, props), + render, + state: { slot: "badge", variant }, }), ); Badge.displayName = "Badge"; diff --git a/ui/litellm-dashboard/src/components/ui/ref-forwarding.test.tsx b/ui/litellm-dashboard/src/components/ui/ref-forwarding.test.tsx index dde91a60de3..48b1e8be226 100644 --- a/ui/litellm-dashboard/src/components/ui/ref-forwarding.test.tsx +++ b/ui/litellm-dashboard/src/components/ui/ref-forwarding.test.tsx @@ -2,6 +2,7 @@ import { render } from "@testing-library/react"; import * as React from "react"; import { describe, expect, it } from "vitest"; +import { Badge } from "./badge"; import { Button } from "./button"; import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./card"; import { ChartContainer } from "./chart"; @@ -13,6 +14,12 @@ import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, Tabl import { UiLoadingSpinner } from "./ui-loading-spinner"; describe("ui primitives forward refs to their DOM node", () => { + it("Badge", () => { + const ref = React.createRef(); + render(ok); + expect(ref.current).toBeInstanceOf(HTMLSpanElement); + }); + it("Button", () => { const ref = React.createRef(); render(); diff --git a/ui/litellm-dashboard/src/components/ui/skeleton.tsx b/ui/litellm-dashboard/src/components/ui/skeleton.tsx index 69ff4891cec..1104379dde6 100644 --- a/ui/litellm-dashboard/src/components/ui/skeleton.tsx +++ b/ui/litellm-dashboard/src/components/ui/skeleton.tsx @@ -4,7 +4,7 @@ import { cn } from "@/lib/cva.config"; const Skeleton = React.forwardRef>( ({ className, ...props }, ref) => ( -
+
), ); Skeleton.displayName = "Skeleton"; diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailContent.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailContent.test.tsx index 01b040b5c17..aab8d2b8cb9 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailContent.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailContent.test.tsx @@ -262,14 +262,14 @@ describe("LogDetailContent", () => { expect(screen.getByText("2 masked")).toBeInTheDocument(); }); - it("should display a green Response Cache 'Hit' tag when the response cache served the request", () => { + it("should display a Response Cache 'Hit' tag when the response cache served the request", () => { render(); expect(screen.getByText("Response Cache")).toBeInTheDocument(); - expect(screen.getByText("Hit").className).toMatch(/green/); + expect(screen.getByText("Hit")).toBeInTheDocument(); }); - it("should show prompt cache tokens without an alarming red tag when only provider prompt caching occurred", () => { + it("should show prompt cache tokens and no response-cache hit when only provider prompt caching occurred", () => { render( { expect(screen.getByText("34,462")).toBeInTheDocument(); expect(screen.getByText("Prompt Cache Creation Tokens")).toBeInTheDocument(); expect(screen.getByText("83")).toBeInTheDocument(); - expect(screen.getByText("Miss").className).not.toMatch(/red|destructive/); + expect(screen.getByText("Miss")).toBeInTheDocument(); expect(screen.queryByText("Cache Hit")).not.toBeInTheDocument(); }); @@ -393,11 +393,10 @@ describe("LogDetailContent", () => { expect(within(retriesItem()).getByText("2 / 3")).toBeInTheDocument(); }); - it("should display a green 'None' tag for Retries when attempted_retries is 0", () => { + it("should display a 'None' tag for Retries when attempted_retries is 0", () => { render(); - const noneTag = within(retriesItem()).getByText("None"); - expect(noneTag.className).toMatch(/green/); + expect(within(retriesItem()).getByText("None")).toBeInTheDocument(); }); it("should display '-' for Retries when attempted_retries is absent from metadata", () => {