Getting Started
Components
- Agent Status
- Agent Template Card
- API Key Card
- Audio Player
- Bar Visualizer
- Channel Status Card
- Chat Composer
- Code Editor
- Condition Builder
- Confirm Dialog
- Conversation
- Conversation Bar
- Dataset Card
- Document Status Badge
- Extraction Strategy Select
- File Icon
- File Upload
- Indexing Progress
- Live Waveform
- Matrix
- Message
- Mic Selector
- Model Diff View
- Model Selector
- Model Type Filter
- Node Catalog
- Option Editor
- Orb
- Output Variables View
- Package Card
- Prompt Editor
- Provider Status Card
- Radio Card
- Resource Card
- Resource Sidebar
- Response
- Run Node List
- Scrub Bar
- Segment Card
- Shimmering Text
- Speech Input
- Token Trend Chart
- Tool Call Card
- Transcript Viewer
- Usage Stat Card
- Variable Binding Editor
- Variable Selector
- Voice Button
- Voice Picker
- Waveform
- Workflow Node Card
- Workspace Selector
Production API
activezgi_live_8x42••••••••agents:rundatasets:readusage:read
Created Jun 12Last used 4 minutes ago
Legacy integration
revokedzgi_live_17fa••••••••agents:run
Created May 20Last used 9 days ago
import { RotateCcwIcon, Trash2Icon } from "lucide-react"
import { ApiKeyCard } from "@/components/ui/api-key-card"
export function ApiKeyCardDemo() {
return (
<div className="w-full max-w-2xl space-y-3">
<ApiKeyCard
name="Production API"
keyPrefix="zgi_live_8x42"
status="active"
scopes={["agents:run", "datasets:read", "usage:read"]}
createdAt="Jun 12"
lastUsedAt="4 minutes ago"
actions={[
{ label: "Rotate", icon: <RotateCcwIcon /> },
{ label: "Revoke", icon: <Trash2Icon /> },
]}
/>
<ApiKeyCard
name="Legacy integration"
keyPrefix="zgi_live_17fa"
status="revoked"
scopes={["agents:run"]}
createdAt="May 20"
lastUsedAt="9 days ago"
/>
</div>
)
}
Installation
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/api-key-card.jsonpnpm dlx shadcn@latest add https://ui.zgi.ai/r/api-key-card.json
yarn dlx shadcn@latest add https://ui.zgi.ai/r/api-key-card.jsonComponent
"use client"
import * as React from "react"
import {
CalendarIcon,
CopyIcon,
KeyRoundIcon,
MoreHorizontalIcon,
} 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"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export interface ApiKeyCardAction {
label: React.ReactNode
icon?: React.ReactNode
onSelect?: () => void
}
export interface ApiKeyCardProps
extends Omit<React.ComponentProps<typeof Card>, "title"> {
name: React.ReactNode
keyPrefix: string
status?: "active" | "expired" | "revoked"
scopes?: React.ReactNode[]
createdAt?: React.ReactNode
lastUsedAt?: React.ReactNode
onCopy?: () => void
actions?: ApiKeyCardAction[]
}
const statusClassName = {
active: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
expired: "bg-amber-500/10 text-amber-700 dark:text-amber-300",
revoked: "bg-destructive/10 text-destructive",
}
export function ApiKeyCard({
name,
keyPrefix,
status = "active",
scopes = [],
createdAt,
lastUsedAt,
onCopy,
actions = [],
className,
...props
}: ApiKeyCardProps) {
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">
<KeyRoundIcon className="size-5" />
</div>
<div className="min-w-0 flex-1">
<div className="flex min-w-0 flex-wrap items-center gap-2">
<h3 className="truncate text-sm font-medium">{name}</h3>
<Badge
variant="secondary"
className={cn(
"h-6 rounded-md border-0",
statusClassName[status]
)}
>
{status}
</Badge>
</div>
<div className="mt-2 flex items-center gap-2">
<code className="bg-muted rounded-md px-2 py-1 text-xs">
{keyPrefix}••••••••
</code>
<Button
type="button"
variant="ghost"
size="icon"
className="size-7 rounded-md"
onClick={onCopy}
aria-label="Copy API key prefix"
>
<CopyIcon className="size-3.5" />
</Button>
</div>
</div>
{actions.length ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
type="button"
variant="ghost"
size="icon"
className="size-8 shrink-0 rounded-md"
aria-label="Open API key actions"
>
<MoreHorizontalIcon className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{actions.map((action, index) => (
<DropdownMenuItem key={index} onSelect={action.onSelect}>
{action.icon ? (
<span className="[&_svg]:size-4">{action.icon}</span>
) : null}
{action.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
) : null}
</div>
{scopes.length ? (
<div className="flex flex-wrap gap-1.5">
{scopes.map((scope, index) => (
<Badge
key={index}
variant="outline"
className="h-6 rounded-md px-2 font-normal"
>
{scope}
</Badge>
))}
</div>
) : null}
<div className="grid gap-2 border-t pt-3 text-xs sm:grid-cols-2">
{createdAt ? (
<span className="text-muted-foreground flex min-w-0 items-center gap-1.5">
<CalendarIcon className="size-3.5 shrink-0" />
<span className="truncate">Created {createdAt}</span>
</span>
) : null}
{lastUsedAt ? (
<span className="text-muted-foreground truncate">
Last used {lastUsedAt}
</span>
) : null}
</div>
</CardContent>
</Card>
)
}
Usage
import { ApiKeyCard } from "@/components/ui/api-key-card"
export function Example() {
return (
<ApiKeyCard
name="Production API"
keyPrefix="zgi_live_8x42"
scopes={["agents:run", "datasets:read"]}
lastUsedAt="4 minutes ago"
/>
)
}Props
| Prop | Type | Default |
|---|---|---|
| name | ReactNode | required |
| keyPrefix | string | required |
| status | "active" | "expired" | "revoked" | "active" |
| scopes | ReactNode[] | [] |
| createdAt | ReactNode | - |
| lastUsedAt | ReactNode | - |
| onCopy | () => void | - |
| actions | ApiKeyCardAction[] | [] |
Deploy and Scale Agents with ZGI
ZGI delivers the infrastructure and developer experience you need to ship reliable audio & agent applications at scale.
Talk to an expert