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
2 routing conditions configured
"use client"
import { useState } from "react"
import {
ConditionBuilder,
type ConditionRule,
} from "@/components/ui/condition-builder"
const fields = [
{ label: "Intent", value: "intent" },
{ label: "Confidence", value: "confidence" },
{ label: "Customer plan", value: "customer.plan" },
]
const initialRules: ConditionRule[] = [
{
id: "confidence",
field: "confidence",
operator: "lt",
value: "0.7",
},
{
id: "plan",
field: "customer.plan",
operator: "equals",
value: "enterprise",
},
]
export function ConditionBuilderDemo() {
const [rules, setRules] = useState(initialRules)
return (
<div className="w-full max-w-3xl space-y-3">
<ConditionBuilder
value={rules}
onValueChange={setRules}
fields={fields}
/>
<p className="text-muted-foreground text-sm">
{rules.length} routing conditions configured
</p>
</div>
)
}
Installation
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/condition-builder.jsonpnpm dlx shadcn@latest add https://ui.zgi.ai/r/condition-builder.json
yarn dlx shadcn@latest add https://ui.zgi.ai/r/condition-builder.jsonComponent
"use client"
import * as React from "react"
import { PlusIcon, Trash2Icon } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
export interface ConditionRule {
id: string
field: string
operator: string
value: string
}
export interface ConditionBuilderOption {
label: string
value: string
}
export interface ConditionBuilderProps extends React.ComponentProps<"div"> {
value: ConditionRule[]
onValueChange?: (value: ConditionRule[]) => void
fields: ConditionBuilderOption[]
operators?: ConditionBuilderOption[]
disabled?: boolean
addText?: string
}
const defaultOperators: ConditionBuilderOption[] = [
{ label: "Equals", value: "equals" },
{ label: "Does not equal", value: "not_equals" },
{ label: "Contains", value: "contains" },
{ label: "Greater than", value: "gt" },
{ label: "Less than", value: "lt" },
{ label: "Exists", value: "exists" },
]
function createRule(fields: ConditionBuilderOption[]): ConditionRule {
return {
id: crypto.randomUUID(),
field: fields[0]?.value ?? "",
operator: "equals",
value: "",
}
}
export function ConditionBuilder({
value,
onValueChange,
fields,
operators = defaultOperators,
disabled = false,
addText = "Add condition",
className,
...props
}: ConditionBuilderProps) {
function updateRule(index: number, patch: Partial<ConditionRule>) {
onValueChange?.(
value.map((rule, ruleIndex) =>
ruleIndex === index ? { ...rule, ...patch } : rule
)
)
}
return (
<div className={cn("space-y-2", className)} {...props}>
{value.map((rule, index) => (
<div
key={rule.id}
className="border-border bg-card grid gap-2 rounded-lg border p-2 sm:grid-cols-[minmax(0,1fr)_160px_minmax(0,1fr)_auto]"
>
<Select
value={rule.field}
onValueChange={(field) => updateRule(index, { field })}
disabled={disabled}
>
<SelectTrigger className="h-9">
<SelectValue placeholder="Field" />
</SelectTrigger>
<SelectContent>
{fields.map((field) => (
<SelectItem key={field.value} value={field.value}>
{field.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Select
value={rule.operator}
onValueChange={(operator) => updateRule(index, { operator })}
disabled={disabled}
>
<SelectTrigger className="h-9">
<SelectValue placeholder="Operator" />
</SelectTrigger>
<SelectContent>
{operators.map((operator) => (
<SelectItem key={operator.value} value={operator.value}>
{operator.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Input
value={rule.value}
onChange={(event) =>
updateRule(index, { value: event.target.value })
}
placeholder="Value"
disabled={disabled || rule.operator === "exists"}
className="h-9"
/>
<Button
type="button"
variant="ghost"
size="icon"
className="size-9 rounded-md"
disabled={disabled}
onClick={() =>
onValueChange?.(
value.filter((_, ruleIndex) => ruleIndex !== index)
)
}
aria-label="Remove condition"
>
<Trash2Icon className="size-4" />
</Button>
</div>
))}
<Button
type="button"
variant="outline"
size="sm"
className="h-8 rounded-md"
disabled={disabled}
onClick={() => onValueChange?.([...value, createRule(fields)])}
>
<PlusIcon className="size-4" />
{addText}
</Button>
</div>
)
}
Usage
import { ConditionBuilder } from "@/components/ui/condition-builder"
export function Example() {
return (
<ConditionBuilder
value={[]}
fields={[{ label: "Confidence", value: "confidence" }]}
/>
)
}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