mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
Merge pull request #36991 from BerriAI/litellm_/blocked-badge-styling-c03b31
refactor(ui): re-sync badge and skeleton onto the base-vega shadcn style
This commit is contained in:
commit
d4a52f9fa5
4 changed files with 28 additions and 29 deletions
|
|
@ -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<typeof badgeVariants> & {
|
||||
render?: useRender.RenderProp;
|
||||
};
|
||||
type BadgeProps = useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>;
|
||||
|
||||
const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
|
||||
({ className, variant = "default", render, ...props }, ref) =>
|
||||
useRender({
|
||||
render: render ?? <span />,
|
||||
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";
|
||||
|
|
|
|||
|
|
@ -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<HTMLSpanElement>();
|
||||
render(<Badge ref={ref}>ok</Badge>);
|
||||
expect(ref.current).toBeInstanceOf(HTMLSpanElement);
|
||||
});
|
||||
|
||||
it("Button", () => {
|
||||
const ref = React.createRef<HTMLButtonElement>();
|
||||
render(<Button ref={ref}>ok</Button>);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { cn } from "@/lib/cva.config";
|
|||
|
||||
const Skeleton = React.forwardRef<HTMLDivElement, React.ComponentPropsWithoutRef<"div">>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} data-slot="skeleton" className={cn("animate-pulse rounded-md bg-accent", className)} {...props} />
|
||||
<div ref={ref} data-slot="skeleton" className={cn("animate-pulse rounded-md bg-muted", className)} {...props} />
|
||||
),
|
||||
);
|
||||
Skeleton.displayName = "Skeleton";
|
||||
|
|
|
|||
|
|
@ -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(<LogDetailContent logEntry={createLogEntry({ cache_hit: "True" })} />);
|
||||
|
||||
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(
|
||||
<LogDetailContent
|
||||
logEntry={createLogEntry({
|
||||
|
|
@ -289,7 +289,7 @@ describe("LogDetailContent", () => {
|
|||
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(<LogDetailContent logEntry={createLogEntry({ metadata: { status: "success", attempted_retries: 0 } })} />);
|
||||
|
||||
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", () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue