@@ -14,30 +14,25 @@ import {
1414 FileText ,
1515 BarChart3 ,
1616 LayoutDashboard ,
17- Settings ,
1817 ChevronLeft ,
19- ChevronRight ,
20- Home ,
21- LogOut ,
22- User ,
2318} from "lucide-react"
2419import { Button } from "@/ui/button"
25- import { ScrollArea } from "@/ui/scroll-area"
26- import { Separator } from "@/ui/separator"
20+ import { Badge } from "@/ui/badge"
2721import {
2822 Tooltip ,
2923 TooltipContent ,
3024 TooltipProvider ,
3125 TooltipTrigger ,
3226} from "@/ui/tooltip"
27+ import { useApiHealthQuery } from "@/lib/hooks/use-dashboard-queries"
3328import {
34- DropdownMenu ,
35- DropdownMenuContent ,
36- DropdownMenuItem ,
37- DropdownMenuLabel ,
38- DropdownMenuSeparator ,
39- DropdownMenuTrigger ,
40- } from "@/ui/dropdown-menu "
29+ Sidebar as UiSidebar ,
30+ SidebarProvider ,
31+ SidebarHeader ,
32+ SidebarContent ,
33+ SidebarFooter ,
34+ SidebarMenuItem ,
35+ } from "@/ui/sidebar "
4136
4237interface NavItem {
4338 title : string
@@ -114,180 +109,92 @@ interface SidebarProps {
114109
115110export function Sidebar ( { collapsed, onCollapsedChange } : SidebarProps ) {
116111 const pathname = usePathname ( )
112+ const { data : apiHealth , isLoading : apiLoading , refetch : refetchApi } = useApiHealthQuery ( )
117113
118114 return (
119115 < TooltipProvider delayDuration = { 0 } >
120- < aside
121- className = { cn (
122- "flex flex-col border-r bg-card transition-all duration-300" ,
123- collapsed ? "w-16" : "w-64"
124- ) }
125- >
126- { /* Header */ }
127- < div className = "flex h-14 items-center justify-between border-b px-4" >
128- { ! collapsed && (
129- < Link href = { "/dashboard" as Route } className = "flex items-center gap-2" >
130- < div className = "flex h-8 w-8 items-center justify-center rounded-lg bg-primary" >
131- < Activity className = "h-4 w-4 text-primary-foreground" />
132- </ div >
133- < span className = "font-semibold" > Mastra Admin</ span >
134- </ Link >
135- ) }
136- { collapsed && (
137- < Link href = { "/dashboard" as Route } className = "mx-auto" >
138- < div className = "flex h-8 w-8 items-center justify-center rounded-lg bg-primary" >
139- < Activity className = "h-4 w-4 text-primary-foreground" />
140- </ div >
141- </ Link >
142- ) }
143- { ! collapsed && (
144- < Button
145- variant = "ghost"
146- size = "icon"
147- onClick = { ( ) => onCollapsedChange ( ! collapsed ) }
148- >
149- < ChevronLeft className = "h-4 w-4" />
150- </ Button >
151- ) }
152- </ div >
153-
154- { /* Expand button when collapsed */ }
155- { collapsed && (
156- < div className = "flex justify-center py-2 border-b" >
157- < Button
158- variant = "ghost"
159- size = "icon"
160- onClick = { ( ) => onCollapsedChange ( false ) }
161- >
162- < ChevronRight className = "h-4 w-4" />
163- </ Button >
164- </ div >
165- ) }
166-
167- { /* Navigation */ }
168- < ScrollArea className = "flex-1 py-2" >
169- < nav className = "flex flex-col gap-1 px-2" >
170- { navItems . map ( ( item ) => {
171- const isActive =
172- pathname === item . href ||
173- ( item . href !== "/dashboard" && pathname . startsWith ( item . href ) )
174-
175- const linkContent = (
176- < Link
177- key = { item . href }
178- href = { item . href as Route }
179- className = { cn (
180- "flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors group" ,
181- isActive
182- ? "bg-primary text-primary-foreground"
183- : "text-muted-foreground hover:bg-accent hover:text-accent-foreground" ,
184- collapsed && "justify-center px-2"
185- ) }
186- >
187- < item . icon className = "h-4 w-4 shrink-0" />
188- { ! collapsed && (
189- < >
190- < span className = "flex-1" > { item . title } </ span >
191- { item . badge && (
192- < span
193- className = { cn (
194- "text-xs px-1.5 py-0.5 rounded-full" ,
195- isActive
196- ? "bg-primary-foreground/20 text-primary-foreground"
197- : "bg-muted text-muted-foreground"
198- ) }
199- >
200- { item . badge }
201- </ span >
202- ) }
203- </ >
204- ) }
205- </ Link >
206- )
116+ < SidebarProvider open = { ! collapsed } onOpenChange = { ( open ) => onCollapsedChange ( ! open ) } >
117+ < UiSidebar collapsible = "icon" >
118+ < SidebarHeader className = "flex items-center justify-between px-4" >
119+ < div className = "flex items-center gap-2" >
120+ < Link href = { '/dashboard' as Route } className = "flex items-center gap-2" >
121+ < div className = "flex h-8 w-8 items-center justify-center rounded-lg bg-primary" >
122+ < Activity className = "h-4 w-4 text-primary-foreground" />
123+ </ div >
124+ { ! collapsed && < span className = "font-semibold" > Mastra Admin</ span > }
125+ </ Link >
126+ </ div >
127+ { ! collapsed && (
128+ < Button variant = "ghost" size = "icon" onClick = { ( ) => onCollapsedChange ( ! collapsed ) } >
129+ < ChevronLeft className = "h-4 w-4" />
130+ </ Button >
131+ ) }
132+ </ SidebarHeader >
207133
208- if ( collapsed ) {
134+ < SidebarContent >
135+ < nav className = "flex flex-col gap-1 px-2" >
136+ { navItems . map ( ( item ) => {
137+ const isActive = pathname === item . href || ( item . href !== '/dashboard' && pathname . startsWith ( item . href ) )
209138 return (
210- < Tooltip key = { item . href } >
211- < TooltipTrigger asChild > { linkContent } </ TooltipTrigger >
212- < TooltipContent side = "right" className = "flex flex-col" >
213- < span className = "font-medium" > { item . title } </ span >
214- { item . description && (
215- < span className = "text-xs text-muted-foreground" >
216- { item . description }
217- </ span >
139+ < SidebarMenuItem key = { item . href } >
140+ < Link
141+ href = { item . href as Route }
142+ className = { cn (
143+ "flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors" ,
144+ isActive ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground" ,
145+ collapsed && "justify-center px-2"
218146 ) }
219- </ TooltipContent >
220- </ Tooltip >
147+ >
148+ < item . icon className = "h-4 w-4 shrink-0" />
149+ { ! collapsed && (
150+ < >
151+ < span className = "flex-1" > { item . title } </ span >
152+ { item . badge ? ( < span className = "text-xs px-1.5 py-0.5 rounded-full bg-muted text-muted-foreground" > { item . badge } </ span > ) : null }
153+ </ >
154+ ) }
155+ </ Link >
156+ </ SidebarMenuItem >
221157 )
222- }
223-
224- return linkContent
225- } ) }
226- </ nav >
227- </ ScrollArea >
228-
229- { /* Footer */ }
230- < div className = "border-t p-2" >
231- < Separator className = "my-2" />
232-
233- { /* Back to Site */ }
234- { collapsed ? (
235- < Tooltip >
236- < TooltipTrigger asChild >
237- < Link
238- href = { "/" as Route }
239- className = "flex items-center justify-center gap-3 rounded-md px-2 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
240- >
241- < Home className = "h-4 w-4 shrink-0" />
242- </ Link >
243- </ TooltipTrigger >
244- < TooltipContent side = "right" > Back to Site</ TooltipContent >
245- </ Tooltip >
246- ) : (
247- < Link
248- href = { "/" as Route }
249- className = "flex items-center gap-3 rounded-md px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
250- >
251- < Home className = "h-4 w-4 shrink-0" />
252- < span > Back to Site</ span >
253- </ Link >
254- ) }
158+ } ) }
159+ </ nav >
160+ </ SidebarContent >
255161
256- { /* User Menu */ }
257- < DropdownMenu >
258- < DropdownMenuTrigger asChild >
259- < button
260- className = { cn (
261- "flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground" ,
262- collapsed && "justify-center px-2"
162+ < SidebarFooter >
163+ < div className = "flex items-center justify-between gap-2" >
164+ < div className = "flex items-center gap-2" >
165+ < span className = "text-xs text-muted-foreground" > API</ span >
166+ { apiHealth ?. ok ? (
167+ < Badge variant = "secondary" className = "text-xs" > OK</ Badge >
168+ ) : apiHealth && ! apiHealth ?. ok ? (
169+ < Tooltip >
170+ < TooltipTrigger asChild >
171+ < Badge variant = "destructive" className = "text-xs cursor-help" > Error</ Badge >
172+ </ TooltipTrigger >
173+ < TooltipContent side = "top" className = "max-w-xs" >
174+ < div className = "text-sm" >
175+ < div className = "font-medium" > API checks failed</ div >
176+ < ul className = "mt-2 text-xs list-disc list-inside" >
177+ { Object . entries ( apiHealth ?. checks ?? { } ) . map ( ( [ k , v ] ) => (
178+ < li key = { k } > { k } : { v ?. ok ? 'ok' : ( v ?. error ?? 'error' ) } </ li >
179+ ) ) }
180+ </ ul >
181+ </ div >
182+ </ TooltipContent >
183+ </ Tooltip >
184+ ) : (
185+ < Badge className = "text-xs" > Unknown</ Badge >
263186 ) }
264- >
265- < div className = "flex h-6 w-6 items-center justify-center rounded-full bg-muted" >
266- < User className = "h-3 w-3" />
267- </ div >
268- { ! collapsed && < span className = "flex-1 text-left" > Account</ span > }
269- </ button >
270- </ DropdownMenuTrigger >
271- < DropdownMenuContent align = { collapsed ? "center" : "start" } side = "top" >
272- < DropdownMenuLabel > My Account</ DropdownMenuLabel >
273- < DropdownMenuSeparator />
274- < DropdownMenuItem asChild >
275- < Link href = { "/dashboard/settings" as Route } >
276- < Settings className = "h-4 w-4 mr-2" />
277- Settings
278- </ Link >
279- </ DropdownMenuItem >
280- < DropdownMenuSeparator />
281- < DropdownMenuItem asChild >
282- < Link href = { "/login" as Route } >
283- < LogOut className = "h-4 w-4 mr-2" />
284- Sign out
285- </ Link >
286- </ DropdownMenuItem >
287- </ DropdownMenuContent >
288- </ DropdownMenu >
289- </ div >
290- </ aside >
187+ </ div >
188+
189+ < div >
190+ < Button size = "sm" variant = "ghost" onClick = { ( ) => refetchApi ( ) } >
191+ Check
192+ </ Button >
193+ </ div >
194+ </ div >
195+ </ SidebarFooter >
196+ </ UiSidebar >
197+ </ SidebarProvider >
291198 </ TooltipProvider >
292199 )
293200}
0 commit comments