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
Support Knowledge
ReadyPolicies, billing answers, and troubleshooting guides for customer-facing agents.
Documents
128
Segments
8,420
SupportRAGProduction
workspace2 hours ago
Product Docs
IndexingMarkdown and PDF documentation currently rebuilding embeddings.
Documents
42
Segments
1,960
DocsEmbedding
privaterunning
import { ArchiveIcon, PencilIcon } from "lucide-react"
import { DatasetCard } from "@/components/ui/dataset-card"
export function DatasetCardDemo() {
return (
<div className="grid w-full max-w-3xl gap-3 sm:grid-cols-2">
<DatasetCard
title="Support Knowledge"
description="Policies, billing answers, and troubleshooting guides for customer-facing agents."
status="ready"
documentCount={128}
segmentCount={8420}
updatedAt="2 hours ago"
visibility="workspace"
tags={["Support", "RAG", "Production"]}
actions={[
{ label: "Edit", icon: <PencilIcon /> },
{ label: "Archive", icon: <ArchiveIcon /> },
]}
/>
<DatasetCard
title="Product Docs"
description="Markdown and PDF documentation currently rebuilding embeddings."
status="indexing"
documentCount={42}
segmentCount={1960}
updatedAt="running"
visibility="private"
tags={["Docs", "Embedding"]}
/>
</div>
)
}
Installation
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/dataset-card.jsonpnpm dlx shadcn@latest add https://ui.zgi.ai/r/dataset-card.json
yarn dlx shadcn@latest add https://ui.zgi.ai/r/dataset-card.jsonComponent
"use client"
import * as React from "react"
import {
DatabaseIcon,
FileTextIcon,
FolderIcon,
LockIcon,
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 type DatasetCardStatus = "ready" | "indexing" | "failed" | "empty"
export interface DatasetCardAction {
label: React.ReactNode
icon?: React.ReactNode
onSelect?: () => void
}
export interface DatasetCardProps
extends Omit<React.ComponentProps<typeof Card>, "title"> {
title: React.ReactNode
description?: React.ReactNode
status?: DatasetCardStatus
documentCount?: number
segmentCount?: number
updatedAt?: React.ReactNode
visibility?: "private" | "workspace" | "public"
tags?: React.ReactNode[]
actions?: DatasetCardAction[]
href?: string
onOpen?: () => void
}
const statusClassName: Record<DatasetCardStatus, string> = {
ready: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
indexing: "bg-blue-500/10 text-blue-700 dark:text-blue-300",
failed: "bg-destructive/10 text-destructive",
empty: "bg-muted text-muted-foreground",
}
const statusLabel: Record<DatasetCardStatus, string> = {
ready: "Ready",
indexing: "Indexing",
failed: "Failed",
empty: "Empty",
}
function Metric({
icon,
label,
}: {
icon: React.ReactNode
label: React.ReactNode
}) {
return (
<span className="text-muted-foreground flex min-w-0 items-center gap-1.5 text-xs">
<span className="[&_svg]:size-3.5">{icon}</span>
<span className="truncate">{label}</span>
</span>
)
}
export function DatasetCard({
title,
description,
status = "ready",
documentCount,
segmentCount,
updatedAt,
visibility = "workspace",
tags = [],
actions = [],
href,
onOpen,
className,
...props
}: DatasetCardProps) {
const content = (
<CardContent className="flex min-h-48 flex-col gap-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">
<DatabaseIcon 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">{title}</h3>
<Badge
variant="secondary"
className={cn("h-6 rounded-md border-0", statusClassName[status])}
>
{statusLabel[status]}
</Badge>
</div>
{description ? (
<p className="text-muted-foreground mt-1 line-clamp-2 text-xs leading-5">
{description}
</p>
) : null}
</div>
{actions.length ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
type="button"
variant="ghost"
size="icon"
className="size-8 shrink-0 rounded-md"
onClick={(event) => event.preventDefault()}
aria-label="Open dataset actions"
>
<MoreHorizontalIcon className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{actions.map((action, index) => (
<DropdownMenuItem
key={index}
onSelect={(event) => {
event.preventDefault()
action.onSelect?.()
}}
>
{action.icon ? (
<span className="[&_svg]:size-4">{action.icon}</span>
) : null}
{action.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
) : null}
</div>
<div className="grid grid-cols-2 gap-2">
{typeof documentCount === "number" ? (
<div className="rounded-md border p-2">
<div className="text-muted-foreground text-xs">Documents</div>
<div className="mt-1 text-sm font-medium tabular-nums">
{documentCount.toLocaleString()}
</div>
</div>
) : null}
{typeof segmentCount === "number" ? (
<div className="rounded-md border p-2">
<div className="text-muted-foreground text-xs">Segments</div>
<div className="mt-1 text-sm font-medium tabular-nums">
{segmentCount.toLocaleString()}
</div>
</div>
) : null}
</div>
{tags.length ? (
<div className="flex flex-wrap gap-1.5">
{tags.map((tag, index) => (
<Badge
key={index}
variant="secondary"
className="h-6 rounded-md px-2 font-normal"
>
{tag}
</Badge>
))}
</div>
) : null}
<div className="mt-auto flex flex-wrap items-center justify-between gap-2 border-t pt-3">
<Metric
icon={visibility === "private" ? <LockIcon /> : <FolderIcon />}
label={visibility}
/>
{updatedAt ? (
<Metric icon={<FileTextIcon />} label={updatedAt} />
) : null}
</div>
</CardContent>
)
return (
<Card
className={cn(
"hover:border-primary/40 hover:bg-accent/20 overflow-hidden rounded-lg py-0 transition-colors",
(href || onOpen) && "cursor-pointer",
className
)}
onClick={onOpen}
{...props}
>
{href ? (
<a href={href} className="block h-full">
{content}
</a>
) : (
content
)}
</Card>
)
}
Usage
import { DatasetCard } from "@/components/ui/dataset-card"
export function Example() {
return (
<DatasetCard
title="Support Knowledge"
status="ready"
documentCount={128}
segmentCount={8420}
tags={["Support", "Production"]}
/>
)
}Props
| Prop | Type | Default |
|---|---|---|
| title | ReactNode | required |
| description | ReactNode | - |
| status | "ready" | "indexing" | "failed" | "empty" | "ready" |
| documentCount | number | - |
| segmentCount | number | - |
| updatedAt | ReactNode | - |
| visibility | "private" | "workspace" | "public" | "workspace" |
| tags | ReactNode[] | [] |
| actions | DatasetCardAction[] | [] |
| href | string | - |
| onOpen | () => void | - |
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