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 base
Embedding policy docs and rebuilding semantic chunks.
Progress68%
Currentsupport-playbook.pdf
Documents
17/25 documents
Chunks
1,842
Failed
1
import { IndexingProgress } from "@/components/ui/indexing-progress"
export function IndexingProgressDemo() {
return (
<IndexingProgress
className="w-full max-w-xl"
title="Support knowledge base"
stage="Embedding policy docs and rebuilding semantic chunks."
progress={68}
status="indexing"
currentFile="support-playbook.pdf"
processedDocuments={17}
totalDocuments={25}
totalChunks={1842}
failedDocuments={1}
/>
)
}
Installation
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/indexing-progress.jsonpnpm dlx shadcn@latest add https://ui.zgi.ai/r/indexing-progress.json
yarn dlx shadcn@latest add https://ui.zgi.ai/r/indexing-progress.jsonComponent
"use client"
import * as React from "react"
import {
AlertCircleIcon,
CheckCircle2Icon,
FileTextIcon,
Loader2Icon,
PauseCircleIcon,
RotateCcwIcon,
} 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 { Progress } from "@/components/ui/progress"
export type IndexingProgressStatus =
| "idle"
| "indexing"
| "complete"
| "failed"
| "paused"
export interface IndexingProgressProps
extends Omit<React.ComponentProps<typeof Card>, "title"> {
title?: React.ReactNode
stage?: React.ReactNode
progress: number
status?: IndexingProgressStatus
currentFile?: React.ReactNode
processedDocuments?: number
totalDocuments?: number
totalChunks?: number
failedDocuments?: number
onRetry?: () => void
}
const statusConfig = {
idle: {
label: "Idle",
icon: FileTextIcon,
className: "bg-muted text-muted-foreground",
},
indexing: {
label: "Indexing",
icon: Loader2Icon,
className: "bg-blue-500/10 text-blue-700 dark:text-blue-300",
},
complete: {
label: "Complete",
icon: CheckCircle2Icon,
className: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
},
failed: {
label: "Failed",
icon: AlertCircleIcon,
className: "bg-destructive/10 text-destructive",
},
paused: {
label: "Paused",
icon: PauseCircleIcon,
className: "bg-amber-500/10 text-amber-700 dark:text-amber-300",
},
} satisfies Record<
IndexingProgressStatus,
{
label: string
icon: React.ComponentType<{ className?: string }>
className: string
}
>
function clampProgress(value: number) {
return Math.max(0, Math.min(100, Math.round(value)))
}
export function IndexingProgress({
title = "Knowledge indexing",
stage,
progress,
status = "indexing",
currentFile,
processedDocuments,
totalDocuments,
totalChunks,
failedDocuments,
onRetry,
className,
...props
}: IndexingProgressProps) {
const normalizedProgress = clampProgress(progress)
const config = statusConfig[status]
const StatusIcon = config.icon
const documentLabel =
typeof processedDocuments === "number" && typeof totalDocuments === "number"
? `${processedDocuments}/${totalDocuments} documents`
: null
return (
<Card className={cn("w-full rounded-lg py-0", className)} {...props}>
<CardContent className="space-y-4 p-4">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<h3 className="truncate text-sm font-medium">{title}</h3>
{stage ? (
<p className="text-muted-foreground mt-1 text-xs leading-5">
{stage}
</p>
) : null}
</div>
<Badge
variant="secondary"
className={cn("h-6 rounded-md border-0", config.className)}
>
<StatusIcon
className={cn(
"size-3.5",
status === "indexing" && "animate-spin"
)}
/>
{config.label}
</Badge>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between gap-3 text-xs">
<span className="text-muted-foreground">Progress</span>
<span className="font-medium tabular-nums">
{normalizedProgress}%
</span>
</div>
<Progress value={normalizedProgress} className="h-2" />
</div>
{currentFile ? (
<div className="bg-muted/60 flex min-h-9 items-center gap-2 rounded-md px-3 text-xs">
<FileTextIcon className="text-muted-foreground size-3.5 shrink-0" />
<span className="text-muted-foreground shrink-0">Current</span>
<span className="truncate font-medium">{currentFile}</span>
</div>
) : null}
<div className="grid grid-cols-2 gap-2 text-xs sm:grid-cols-4">
{documentLabel ? (
<div className="rounded-md border p-2">
<div className="text-muted-foreground">Documents</div>
<div className="mt-1 font-medium tabular-nums">
{documentLabel}
</div>
</div>
) : null}
{typeof totalChunks === "number" ? (
<div className="rounded-md border p-2">
<div className="text-muted-foreground">Chunks</div>
<div className="mt-1 font-medium tabular-nums">
{totalChunks.toLocaleString()}
</div>
</div>
) : null}
{typeof failedDocuments === "number" ? (
<div className="rounded-md border p-2">
<div className="text-muted-foreground">Failed</div>
<div className="mt-1 font-medium tabular-nums">
{failedDocuments}
</div>
</div>
) : null}
{onRetry ? (
<Button
type="button"
variant="outline"
size="sm"
className="h-auto min-h-12 justify-start gap-2 rounded-md"
onClick={onRetry}
>
<RotateCcwIcon className="size-3.5" />
Retry
</Button>
) : null}
</div>
</CardContent>
</Card>
)
}
Usage
import { IndexingProgress } from "@/components/ui/indexing-progress"
export function Example() {
return (
<IndexingProgress
progress={68}
status="indexing"
currentFile="support-playbook.pdf"
processedDocuments={17}
totalDocuments={25}
totalChunks={1842}
/>
)
}Props
| Prop | Type | Default |
|---|---|---|
| progress | number | required |
| status | "idle" | "indexing" | "complete" | "failed" | "paused" | "indexing" |
| title | ReactNode | "Knowledge indexing" |
| stage | ReactNode | - |
| currentFile | ReactNode | - |
| processedDocuments | number | - |
| totalDocuments | number | - |
| totalChunks | number | - |
| failedDocuments | number | - |
| onRetry | () => 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