Getting Started
Components
- Agent Status
- Agent Template Card
- API Key Card
- Button
- Channel Status Card
- Chat Composer
- Code Editor
- Condition Builder
- Confirm Dialog
- Conversation
- Dataset Card
- Document Status Badge
- Extraction Strategy Select
- File Icon
- File Upload
- Indexing Progress
- Matrix
- Message
- Model Diff View
- Model Selector
- Model Type Filter
- Node Catalog
- Option Editor
- Output Variables View
- Package Card
- Prompt Editor
- Provider Status Card
- Radio Card
- Resource Card
- Resource Sidebar
- Response
- Run Node List
- Segment Card
- Shimmering Text
- Token Trend Chart
- Tool Call Card
- Usage Stat Card
- Variable Binding Editor
- Variable Selector
- Workflow Node Card
- Workspace Selector
ZZGI Agent ConsoleProduction
99.98% uptimeSynced 4 min ago
Agent workspace3 active workflows
Support Agent Overview
Monitor active workflow routing, knowledge coverage, and release health from one resource view.
Runs today
12.8k
+18%
Policy pass
99.4%
Guarded
Avg latency
612ms
-42ms
Active workflow
RunningPrompt router
LLM intent
Knowledge search
RAG + citations
Escalation
Policy gate
Current run trace1.8s elapsed
Channels
Website chatConnected
Email handoffReady
Slack alertsMuted
import {
ActivityIcon,
BotIcon,
CheckCircle2Icon,
Clock3Icon,
DatabaseIcon,
FilesIcon,
GaugeIcon,
GitBranchIcon,
Layers3Icon,
MessageSquareIcon,
SearchIcon,
SettingsIcon,
ShieldCheckIcon,
SparklesIcon,
WorkflowIcon,
ZapIcon,
} from "lucide-react"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { ResourceSidebar } from "@/components/ui/resource-sidebar"
const navItems = [
{
title: "Overview",
href: "#overview",
icon: <BotIcon />,
active: true,
},
{
title: "Knowledge",
href: "#knowledge",
icon: <DatabaseIcon />,
children: [
{ title: "Datasets", href: "#datasets", icon: <FilesIcon /> },
{ title: "Retrieval", href: "#retrieval", icon: <SettingsIcon /> },
],
},
{
title: "Workflows",
href: "#workflows",
icon: <WorkflowIcon />,
},
]
export function ResourceSidebarDemo() {
return (
<div className="bg-surface @container relative w-full max-w-5xl overflow-hidden rounded-lg border p-2 shadow-[0_12px_40px_rgba(10,11,13,0.06)]">
<div className="bg-background mb-2 flex h-9 items-center justify-between rounded-lg border px-3">
<div className="flex items-center gap-2">
<span className="bg-primary text-primary-foreground flex size-5 items-center justify-center rounded-md text-[11px] font-bold">
Z
</span>
<span className="text-xs font-semibold">ZGI Agent Console</span>
<Badge
variant="secondary"
className="h-5 rounded-md px-1.5 text-[10px]"
>
Production
</Badge>
</div>
<div className="text-muted-foreground flex items-center gap-3 text-[11px]">
<span className="inline-flex items-center gap-1">
<ActivityIcon className="size-3.5 text-emerald-500" />
99.98% uptime
</span>
<span className="hidden items-center gap-1 sm:inline-flex">
<Clock3Icon className="size-3.5" />
Synced 4 min ago
</span>
</div>
</div>
<div className="bg-card grid h-[390px] grid-cols-[184px_minmax(0,1fr)] overflow-hidden rounded-lg border @[920px]:h-[492px] @[920px]:grid-cols-[236px_minmax(0,1fr)_260px]">
<ResourceSidebar
className="bg-background h-full"
expandedClassName="w-[184px] @[920px]:w-[236px]"
title="Support Agent"
description="Production agent for support and escalation."
icon={<BotIcon className="size-5" />}
backHref="#"
navItems={navItems}
footer={
<div className="bg-surface rounded-lg border p-2.5">
<div className="flex items-center justify-between gap-2">
<span className="text-muted-foreground text-xs">
Release channel
</span>
<Badge className="bg-primary text-primary-foreground h-5 rounded-md px-1.5 text-[10px]">
Live
</Badge>
</div>
<div className="text-muted-foreground mt-2 flex items-center gap-1.5 text-[11px]">
<GitBranchIcon className="size-3.5" />
v0.9.8 deployed
</div>
</div>
}
/>
<main className="bg-background flex min-w-0 flex-col">
<div className="border-b p-3 @[920px]:p-5">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<div className="mb-2 flex items-center gap-2">
<Badge
variant="outline"
className="border-primary/20 bg-primary/5 text-primary h-5 rounded-md px-1.5 text-[10px]"
>
Agent workspace
</Badge>
<span className="text-muted-foreground text-[11px]">
3 active workflows
</span>
</div>
<h3 className="truncate text-base font-semibold">
Support Agent Overview
</h3>
<p className="text-muted-foreground mt-1 text-xs leading-5">
Monitor active workflow routing, knowledge coverage, and
release health from one resource view.
</p>
</div>
<Button size="sm">
<ZapIcon className="size-3.5" />
Deploy
</Button>
</div>
</div>
<div className="grid gap-2 p-3 sm:grid-cols-3 @[920px]:gap-3 @[920px]:p-5">
{[
{
label: "Runs today",
value: "12.8k",
trend: "+18%",
icon: <ActivityIcon />,
},
{
label: "Policy pass",
value: "99.4%",
trend: "Guarded",
icon: <ShieldCheckIcon />,
},
{
label: "Avg latency",
value: "612ms",
trend: "-42ms",
icon: <GaugeIcon />,
},
].map((item) => (
<div
key={item.label}
className="bg-background rounded-lg border p-3"
>
<div className="flex items-center justify-between gap-2">
<div className="text-muted-foreground text-xs">
{item.label}
</div>
<span className="text-primary bg-primary/10 flex size-6 items-center justify-center rounded-md [&_svg]:size-3.5">
{item.icon}
</span>
</div>
<div className="mt-2 flex items-end justify-between gap-2">
<div className="text-lg font-semibold">{item.value}</div>
<div className="text-muted-foreground text-[11px]">
{item.trend}
</div>
</div>
</div>
))}
</div>
<div className="grid min-h-0 flex-1 gap-2 px-3 pb-3 sm:grid-cols-[1.1fr_0.9fr] @[920px]:gap-3 @[920px]:px-5 @[920px]:pb-5">
<div className="bg-background rounded-lg border p-3.5">
<div className="flex items-center justify-between gap-3">
<div className="flex items-center gap-2 text-sm font-medium">
<WorkflowIcon className="text-primary size-4" />
Active workflow
</div>
<Badge
variant="secondary"
className="h-5 rounded-md text-[10px]"
>
Running
</Badge>
</div>
<div className="mt-4 grid grid-cols-[1fr_auto_1fr_auto_1fr] items-center gap-2">
{[
{
label: "Prompt router",
meta: "LLM intent",
icon: <SparklesIcon />,
},
{
label: "Knowledge search",
meta: "RAG + citations",
icon: <SearchIcon />,
},
{
label: "Escalation",
meta: "Policy gate",
icon: <GitBranchIcon />,
},
].map((node, index) => (
<div key={node.label} className="contents">
<div className="bg-surface min-w-0 rounded-lg border p-2.5">
<div className="text-primary bg-primary/10 flex size-7 items-center justify-center rounded-md [&_svg]:size-3.5">
{node.icon}
</div>
<div className="mt-2 truncate text-xs font-medium">
{node.label}
</div>
<div className="text-muted-foreground mt-0.5 truncate text-[11px]">
{node.meta}
</div>
</div>
{index < 2 ? (
<div className="from-primary/20 via-primary/60 to-primary/20 h-px w-5 bg-gradient-to-r" />
) : null}
</div>
))}
</div>
<div className="border-primary/10 bg-primary/[0.03] mt-3 rounded-lg border p-2.5">
<div className="flex items-center justify-between text-[11px]">
<span className="text-muted-foreground">
Current run trace
</span>
<span className="text-primary font-medium">1.8s elapsed</span>
</div>
<div className="bg-primary/10 mt-2 h-1.5 overflow-hidden rounded-full">
<div className="bg-primary h-full w-[72%] rounded-full" />
</div>
</div>
</div>
<div className="bg-background rounded-lg border p-3.5">
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 text-sm font-medium">
<MessageSquareIcon className="text-primary size-4" />
Channels
</div>
<CheckCircle2Icon className="size-4 text-emerald-500" />
</div>
<div className="mt-3 space-y-2 text-xs">
{[
["Website chat", "Connected"],
["Email handoff", "Ready"],
["Slack alerts", "Muted"],
].map(([label, value]) => (
<div
key={label}
className="bg-surface flex items-center justify-between rounded-md border px-2.5 py-2"
>
<span className="text-muted-foreground">{label}</span>
<span className="font-medium">{value}</span>
</div>
))}
</div>
</div>
</div>
</main>
<aside className="bg-surface hidden min-w-0 flex-col border-l @[920px]:flex">
<div className="border-b p-4">
<div className="flex items-center gap-2 text-sm font-semibold">
<Layers3Icon className="text-primary size-4" />
Inspector
</div>
<p className="text-muted-foreground mt-1 text-xs leading-5">
Live configuration, policy, and knowledge health for this
resource.
</p>
</div>
<div className="space-y-3 p-4">
<div className="bg-background rounded-lg border p-3">
<div className="text-muted-foreground text-[11px] uppercase">
Model
</div>
<div className="mt-1 text-sm font-medium">ZGI Agent Pro</div>
<div className="text-muted-foreground mt-1 text-xs">
Temperature 0.2, tool routing on
</div>
</div>
<div className="bg-background rounded-lg border p-3">
<div className="flex items-center justify-between text-xs">
<span className="text-muted-foreground">
Knowledge coverage
</span>
<span className="font-medium">94%</span>
</div>
<div className="bg-primary/10 mt-2 h-1.5 rounded-full">
<div className="bg-primary h-full w-[94%] rounded-full" />
</div>
</div>
<div className="bg-background rounded-lg border p-3">
<div className="text-muted-foreground text-[11px] uppercase">
Guardrails
</div>
<div className="mt-2 space-y-2 text-xs">
<div className="flex items-center justify-between">
<span>PII redaction</span>
<Badge
variant="outline"
className="h-5 rounded-md text-[10px]"
>
On
</Badge>
</div>
<div className="flex items-center justify-between">
<span>Human handoff</span>
<Badge
variant="outline"
className="h-5 rounded-md text-[10px]"
>
Auto
</Badge>
</div>
</div>
</div>
</div>
</aside>
</div>
</div>
)
}
Installation
pnpm dlx shadcn@latest add https://ui.zgi.ai/r/resource-sidebar.jsonpnpm dlx shadcn@latest add https://ui.zgi.ai/r/resource-sidebar.json
yarn dlx shadcn@latest add https://ui.zgi.ai/r/resource-sidebar.jsonComponent
"use client"
import * as React from "react"
import {
ArrowLeftIcon,
PanelLeftCloseIcon,
PanelLeftOpenIcon,
} from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Skeleton } from "@/components/ui/skeleton"
export interface ResourceSidebarNavItem {
title: React.ReactNode
href?: string
icon?: React.ReactNode
active?: boolean
children?: ResourceSidebarNavItem[]
onSelect?: () => void
}
export interface ResourceSidebarProps
extends Omit<React.ComponentProps<"aside">, "title"> {
collapsed?: boolean
onCollapsedChange?: (collapsed: boolean) => void
title?: React.ReactNode
description?: React.ReactNode
icon?: React.ReactNode
backHref?: string
backLabel?: React.ReactNode
navItems?: ResourceSidebarNavItem[]
footer?: React.ReactNode
loading?: boolean
expandedClassName?: string
}
function SidebarLink({
item,
collapsed,
depth = 0,
}: {
item: ResourceSidebarNavItem
collapsed?: boolean
depth?: number
}) {
const isChild = depth > 0
const content = (
<>
{item.active && !collapsed ? (
<span
className={cn(
"absolute top-2 bottom-2 rounded-full",
isChild ? "bg-primary/70 left-3 w-0.5" : "bg-primary left-0.5 w-1"
)}
aria-hidden="true"
/>
) : null}
{item.icon ? (
<span
className={cn(
"flex size-7 shrink-0 items-center justify-center rounded-md transition-colors [&_svg]:size-4",
item.active
? "bg-primary/10 text-primary"
: "text-muted-foreground group-hover/link:bg-muted group-hover/link:text-foreground",
isChild && "size-5 bg-transparent"
)}
>
{item.icon}
</span>
) : null}
<span
className={cn(
"truncate transition-all",
collapsed ? "w-0 opacity-0" : "w-full opacity-100",
isChild ? "text-xs" : "text-sm"
)}
>
{item.title}
</span>
</>
)
const className = cn(
"group/link relative flex min-h-9 items-center gap-2 rounded-md px-2.5 font-medium text-muted-foreground transition-colors hover:bg-muted/70 hover:text-foreground",
item.active && "bg-primary/5 text-foreground",
collapsed && "w-8 justify-center px-0",
isChild && !collapsed && "ml-5 min-h-8 pl-5 text-sm font-normal"
)
if (item.href) {
return (
<a href={item.href} className={className} onClick={item.onSelect}>
{content}
</a>
)
}
return (
<button type="button" className={className} onClick={item.onSelect}>
{content}
</button>
)
}
export function ResourceSidebar({
collapsed = false,
onCollapsedChange,
title,
description,
icon,
backHref,
backLabel = "Back",
navItems = [],
footer,
loading = false,
expandedClassName = "w-56",
className,
...props
}: ResourceSidebarProps) {
const ToggleIcon = collapsed ? PanelLeftOpenIcon : PanelLeftCloseIcon
return (
<aside
className={cn(
"bg-background relative flex h-full shrink-0 flex-col border-r transition-all",
collapsed ? "w-12" : expandedClassName,
className
)}
{...props}
>
<div className="border-b p-3">
<div className="flex items-center justify-between gap-2">
{backHref && !collapsed ? (
<a
href={backHref}
className="text-muted-foreground hover:bg-muted hover:text-foreground inline-flex min-w-0 items-center gap-1 rounded-md px-1.5 py-1 text-xs transition-colors"
>
<ArrowLeftIcon className="size-3.5" />
<span className="truncate">{backLabel}</span>
</a>
) : (
<span />
)}
<Button
type="button"
variant="ghost"
size="icon"
className="text-muted-foreground hover:text-foreground size-8 rounded-md"
onClick={() => onCollapsedChange?.(!collapsed)}
aria-label={collapsed ? "Expand sidebar" : "Collapse sidebar"}
>
<ToggleIcon className="size-4" />
</Button>
</div>
<div
className={cn(
"mt-2 flex min-w-0 items-center gap-2",
collapsed && "justify-center"
)}
>
{loading ? (
<Skeleton className="size-9 rounded-lg" />
) : (
<div className="bg-primary/10 text-primary flex size-10 shrink-0 items-center justify-center rounded-lg">
{icon}
</div>
)}
<div className={cn("min-w-0 flex-1", collapsed && "hidden")}>
{loading ? (
<div className="space-y-1">
<Skeleton className="h-3.5 w-24" />
<Skeleton className="h-3 w-32" />
</div>
) : (
<>
<div className="truncate text-sm font-semibold">{title}</div>
{description ? (
<div className="text-muted-foreground mt-0.5 line-clamp-2 text-xs leading-5">
{description}
</div>
) : null}
</>
)}
</div>
</div>
</div>
<nav className="flex flex-1 flex-col gap-1 p-3">
{navItems.map((item, index) => (
<div key={index} className="space-y-1">
<SidebarLink item={item} collapsed={collapsed} />
{!collapsed && item.children?.length ? (
<div className="border-border/70 ml-4 space-y-1 border-l py-1">
{item.children.map((child, childIndex) => (
<SidebarLink key={childIndex} item={child} depth={1} />
))}
</div>
) : null}
</div>
))}
</nav>
{footer && !collapsed ? (
<div className="border-t p-2">{footer}</div>
) : null}
</aside>
)
}
Usage
import { BotIcon } from "lucide-react"
import { ResourceSidebar } from "@/components/ui/resource-sidebar"
export function Example() {
return (
<ResourceSidebar
title="Support Agent"
icon={<BotIcon className="size-5" />}
navItems={[{ title: "Overview", href: "#", active: true }]}
/>
)
}Props
| Prop | Type | Default |
|---|---|---|
| collapsed | boolean | false |
| onCollapsedChange | (collapsed: boolean) => void | - |
| title | ReactNode | - |
| description | ReactNode | - |
| icon | ReactNode | - |
| backHref | string | - |
| navItems | ResourceSidebarNavItem[] | [] |
| footer | ReactNode | - |
| loading | boolean | false |
Deploy and Scale Agents with ZGI
ZGI delivers the infrastructure and developer experience you need to ship reliable agent, workflow, and knowledge applications at scale.
Talk to an expert