-

Provider Status Card

PreviousNext

A provider health card for model catalog sync, balance, latency, and actions.

Installation

pnpm
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/provider-status-card.json
npm
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/provider-status-card.json
yarn
yarn dlx shadcn@latest add https://ui.zgi.ai/r/provider-status-card.json

Component

components/ui/provider-status-card.tsx
"use client"

import * as React from "react"
import {
  AlertCircleIcon,
  CheckCircle2Icon,
  Clock3Icon,
  Loader2Icon,
  PlugZapIcon,
  PowerOffIcon,
} from "lucide-react"

import { cn } from "@/lib/utils"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"

export type ProviderStatus = "connected" | "syncing" | "error" | "disabled"

export interface ProviderStatusAction {
  label: React.ReactNode
  icon?: React.ReactNode
  onSelect?: () => void
}

export interface ProviderStatusCardProps
  extends Omit<React.ComponentProps<typeof Card>, "title"> {
  name: React.ReactNode
  description?: React.ReactNode
  status?: ProviderStatus
  icon?: React.ReactNode
  modelCount?: number
  balance?: React.ReactNode
  latency?: React.ReactNode
  lastSync?: React.ReactNode
  actions?: ProviderStatusAction[]
}

const providerStatusConfig = {
  connected: {
    label: "Connected",
    icon: CheckCircle2Icon,
    className: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
  },
  syncing: {
    label: "Syncing",
    icon: Loader2Icon,
    className: "bg-blue-500/10 text-blue-700 dark:text-blue-300",
  },
  error: {
    label: "Error",
    icon: AlertCircleIcon,
    className: "bg-destructive/10 text-destructive",
  },
  disabled: {
    label: "Disabled",
    icon: PowerOffIcon,
    className: "bg-muted text-muted-foreground",
  },
} satisfies Record<
  ProviderStatus,
  {
    label: string
    icon: React.ComponentType<{ className?: string }>
    className: string
  }
>

export function ProviderStatusCard({
  name,
  description,
  status = "connected",
  icon,
  modelCount,
  balance,
  latency,
  lastSync,
  actions = [],
  className,
  ...props
}: ProviderStatusCardProps) {
  const config = providerStatusConfig[status]
  const StatusIcon = config.icon

  return (
    <Card className={cn("rounded-lg py-0", className)} {...props}>
      <CardContent className="space-y-4 p-4">
        <div className="flex items-start gap-3">
          <div className="bg-muted text-muted-foreground flex size-10 shrink-0 items-center justify-center rounded-lg">
            {icon ?? <PlugZapIcon className="size-5" />}
          </div>
          <div className="min-w-0 flex-1">
            <div className="flex min-w-0 items-center gap-2">
              <h3 className="truncate text-sm font-medium">{name}</h3>
              <Badge
                variant="secondary"
                className={cn("h-6 rounded-md border-0", config.className)}
              >
                <StatusIcon
                  className={cn(
                    "size-3.5",
                    status === "syncing" && "animate-spin"
                  )}
                />
                {config.label}
              </Badge>
            </div>
            {description ? (
              <p className="text-muted-foreground mt-1 line-clamp-2 text-xs leading-5">
                {description}
              </p>
            ) : null}
          </div>
        </div>

        <div className="grid grid-cols-3 gap-2 text-xs">
          {typeof modelCount === "number" ? (
            <div className="rounded-md border p-2">
              <div className="text-muted-foreground">Models</div>
              <div className="mt-1 font-medium tabular-nums">{modelCount}</div>
            </div>
          ) : null}
          {balance ? (
            <div className="rounded-md border p-2">
              <div className="text-muted-foreground">Balance</div>
              <div className="mt-1 truncate font-medium">{balance}</div>
            </div>
          ) : null}
          {latency ? (
            <div className="rounded-md border p-2">
              <div className="text-muted-foreground">Latency</div>
              <div className="mt-1 truncate font-medium">{latency}</div>
            </div>
          ) : null}
        </div>

        <div className="flex flex-wrap items-center justify-between gap-3 border-t pt-3">
          {lastSync ? (
            <span className="text-muted-foreground flex items-center gap-1.5 text-xs">
              <Clock3Icon className="size-3.5" />
              {lastSync}
            </span>
          ) : (
            <span />
          )}
          {actions.length ? (
            <div className="flex flex-wrap gap-2">
              {actions.map((action, index) => (
                <Button
                  key={index}
                  type="button"
                  variant={index === 0 ? "default" : "outline"}
                  size="sm"
                  className="h-8 gap-2 rounded-md"
                  onClick={action.onSelect}
                >
                  {action.icon ? (
                    <span className="[&_svg]:size-3.5">{action.icon}</span>
                  ) : null}
                  {action.label}
                </Button>
              ))}
            </div>
          ) : null}
        </div>
      </CardContent>
    </Card>
  )
}

Usage

import { ProviderStatusCard } from "@/components/ui/provider-status-card"
 
export function Example() {
  return (
    <ProviderStatusCard
      name="ZGI Inference"
      status="connected"
      modelCount={18}
      balance="$1,284"
      latency="184 ms"
      lastSync="Synced 4 min ago"
    />
  )
}

Props

PropTypeDefault
nameReactNoderequired
descriptionReactNode-
status"connected" | "syncing" | "error" | "disabled""connected"
iconReactNode-
modelCountnumber-
balanceReactNode-
latencyReactNode-
lastSyncReactNode-
actionsProviderStatusAction[][]