Skip to content

Commit

Permalink
feat: add views category (#16)
Browse files Browse the repository at this point in the history
Fix #6
  • Loading branch information
MattKetmo authored Nov 12, 2024
1 parent 37e7b36 commit 8cfee52
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 25 deletions.
93 changes: 72 additions & 21 deletions src/components/layout/app-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client'

import { Bell, Bookmark, CircleSlash2, LayoutGrid, Rows3, Settings2, SquareDot, Tag } from "lucide-react"
import Link from "next/link"
import { Bell, Bookmark, ChevronRight, CircleSlash2, LayoutGrid, Rows3, Settings2, SquareDot, Tag } from "lucide-react"
import {
Sidebar,
SidebarContent,
Expand All @@ -10,15 +11,19 @@ import {
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuBadge,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarRail,
SidebarTrigger,
} from "@/components/ui/sidebar"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
import { DarkModeToggle } from "./dark-mode-toggle"
import Link from "next/link"
import { useConfig } from "@/contexts/config"
import { useAlerts } from "@/contexts/alerts"
import { alertFilter, flattenAlerts } from "../alerts/utils"
import { alertFilter, flattenAlerts } from "@/components/alerts/utils"
import { ViewConfig } from "@/config/types"

const items = [
{
Expand All @@ -38,14 +43,29 @@ const items = [
},
]

type CategorizedViews = { [key: string]: { handle: string, view: ViewConfig }[] }

export function AppSidebar() {
const { config } = useConfig()
const { views } = config
const { views, viewCategories } = config
const { alerts } = useAlerts()

const flatAlerts = flattenAlerts(alerts)

// Group views by category
const categorizedViews = Object.entries(views).reduce((acc: CategorizedViews, [handle, view]) => {
if (handle !== 'default') {
const category = view.category || '__uncategorized__';
if (!acc[category]) {
acc[category] = [];
}
acc[category].push({ handle, view });
}
return acc;
}, {});
const uncategorizedViews = categorizedViews.__uncategorized__ || [];
delete categorizedViews.__uncategorized__;

return (
<Sidebar>
{/* <SidebarHeader>
Expand Down Expand Up @@ -80,30 +100,61 @@ export function AppSidebar() {
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{Object.entries(views).map(([handle, view]) => (
handle === 'default' ? null : (
<SidebarMenuItem key={handle}>
<SidebarMenuButton asChild>
<Link href={`/alerts/${handle}`}>
{Object.entries(categorizedViews).map(([category, views]) => (
<Collapsible defaultOpen className="group/collapsible" key={category}>
<SidebarMenuItem>
<CollapsibleTrigger asChild>
<SidebarMenuButton >
<SquareDot />
<div className="flex items-baseline gap-2 w-full">
<span className="shrink-0 grow">{view.name || handle}</span>
<span className="shrink-0 text-xs text-muted-foreground bg-secondary p-1 w-6 text-center rounded-sm">
{flatAlerts.filter(alertFilter(view.filters)).length}
</span>
</div>
</Link>
</SidebarMenuButton>
<span>{viewCategories[category]?.name || category}</span>
<ChevronRight className="transition-transform ml-auto group-data-[state=open]/collapsible:rotate-90" />
</SidebarMenuButton>
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
{views.map(({ handle, view }) => (
<SidebarMenuItem key={handle}>
<SidebarMenuButton asChild>
<Link href={`/alerts/${handle}`}>
<div className="flex items-baseline gap-2 w-full pr-12">
<span className="truncate grow">{view.name || handle}</span>
</div>
</Link>
</SidebarMenuButton>
<SidebarMenuBadge className="text-muted-foreground bg-secondary rounded-sm">
{flatAlerts.filter(alertFilter(view.filters)).length}
</SidebarMenuBadge>
</SidebarMenuItem>
))}
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
)))}
</Collapsible>
))}
{uncategorizedViews.map(({ handle, view }) => (
<SidebarMenuItem key={handle}>
<SidebarMenuButton asChild>
<Link href={`/alerts/${handle}`}>
<div className="flex items-baseline gap-2 w-full pr-12">
<span className="truncate grow">{view.name || handle}</span>
</div>
</Link>
</SidebarMenuButton>
<SidebarMenuBadge className="text-muted-foreground bg-secondary rounded-sm">
{flatAlerts.filter(alertFilter(view.filters)).length}
</SidebarMenuBadge>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent >

</SidebarContent>
<SidebarFooter className="flex items-end justify-end">
<SidebarFooter className="flex items-end justify-end border-t">
<DarkModeToggle />
</SidebarFooter>
</Sidebar>

<SidebarRail />
</Sidebar >
)
}
2 changes: 1 addition & 1 deletion src/components/ui/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ const SidebarMenuSub = React.forwardRef<
ref={ref}
data-sidebar="menu-sub"
className={cn(
"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5",
"ml-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border pl-2.5 py-0.5",
"group-data-[collapsible=icon]:hidden",
className
)}
Expand Down
11 changes: 8 additions & 3 deletions src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ const ClusterSchema = z.object({
labels: z.record(z.string()),
})

export type ClusterConfig = z.infer<typeof ClusterSchema>
export const ViewCategorySchema = z.object({
name: z.string(),
})

export const ViewsSchema = z.object({
name: z.string().optional().default(''),
groupBy: z.string(),
category: z.string().optional().default(''),
filters: z.array(
z.object({
label: z.string(),
Expand All @@ -23,11 +26,13 @@ export const ViewsSchema = z.object({
),
})

export type ViewConfig = z.infer<typeof ViewsSchema>

export const ConfigSchema = z.object({
clusters: z.array(ClusterSchema),
viewCategories: z.record(ViewCategorySchema),
views: z.record(ViewsSchema),
})

export type ClusterConfig = z.infer<typeof ClusterSchema>
export type ViewCategoryConfig = z.infer<typeof ViewCategorySchema>
export type ViewConfig = z.infer<typeof ViewsSchema>
export type Config = z.infer<typeof ConfigSchema>

0 comments on commit 8cfee52

Please sign in to comment.