Pipeline/frontend/src/components/organisms/DashboardSidebar.tsx

271 lines
9.4 KiB
TypeScript
Raw Normal View History

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import {
Activity,
BarChart3,
Bot,
Boxes,
CheckCircle2,
Folder,
Building2,
LayoutGrid,
Network,
Settings,
Store,
Tags,
} from "lucide-react";
import { useAuth } from "@/auth/clerk";
import { ApiError } from "@/api/mutator";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import {
type healthzHealthzGetResponse,
useHealthzHealthzGet,
} from "@/api/generated/default/default";
import { cn } from "@/lib/utils";
export function DashboardSidebar() {
const pathname = usePathname();
const { isSignedIn } = useAuth();
const { isAdmin } = useOrganizationMembership(isSignedIn);
const healthQuery = useHealthzHealthzGet<healthzHealthzGetResponse, ApiError>(
{
query: {
refetchInterval: 30_000,
refetchOnMount: "always",
retry: false,
},
request: { cache: "no-store" },
},
);
const okValue = healthQuery.data?.data?.ok;
const systemStatus: "unknown" | "operational" | "degraded" =
okValue === true
? "operational"
: okValue === false
? "degraded"
: healthQuery.isError
? "degraded"
: "unknown";
const statusLabel =
systemStatus === "operational"
? "All systems operational"
: systemStatus === "unknown"
? "System status unavailable"
: "System degraded";
return (
<aside className="fixed inset-y-0 left-0 z-40 flex w-[280px] -translate-x-full flex-col border-r border-slate-200 bg-white pt-16 shadow-lg transition-transform duration-200 ease-in-out [[data-sidebar=open]_&]:translate-x-0 md:relative md:inset-auto md:z-auto md:w-[260px] md:translate-x-0 md:pt-0 md:shadow-none md:transition-none">
<div className="flex-1 px-3 py-4">
<p className="px-3 text-xs font-semibold uppercase tracking-wider text-slate-500">
Navigation
</p>
<nav className="mt-3 space-y-4 text-sm">
<div>
<p className="px-3 text-[11px] font-semibold uppercase tracking-wider text-slate-400">
Overview
</p>
<div className="mt-1 space-y-1">
<Link
href="/dashboard"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname === "/dashboard"
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<BarChart3 className="h-4 w-4" />
Dashboard
</Link>
<Link
href="/activity"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/activity")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<Activity className="h-4 w-4" />
Live feed
</Link>
</div>
</div>
<div>
<p className="px-3 text-[11px] font-semibold uppercase tracking-wider text-slate-400">
Boards
</p>
<div className="mt-1 space-y-1">
<Link
href="/board-groups"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/board-groups")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<Folder className="h-4 w-4" />
Board groups
</Link>
<Link
href="/boards"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/boards")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<LayoutGrid className="h-4 w-4" />
Boards
</Link>
<Link
href="/tags"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/tags")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<Tags className="h-4 w-4" />
Tags
</Link>
<Link
href="/approvals"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/approvals")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<CheckCircle2 className="h-4 w-4" />
Approvals
</Link>
{isAdmin ? (
<Link
href="/custom-fields"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/custom-fields")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<Settings className="h-4 w-4" />
Custom fields
</Link>
) : null}
</div>
</div>
<div>
{isAdmin ? (
<>
<p className="px-3 text-[11px] font-semibold uppercase tracking-wider text-slate-400">
Skills
</p>
<div className="mt-1 space-y-1">
<Link
href="/skills/marketplace"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname === "/skills" ||
pathname.startsWith("/skills/marketplace")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<Store className="h-4 w-4" />
Marketplace
</Link>
<Link
href="/skills/packs"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/skills/packs")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<Boxes className="h-4 w-4" />
Packs
</Link>
</div>
</>
) : null}
</div>
<div>
<p className="px-3 text-[11px] font-semibold uppercase tracking-wider text-slate-400">
Administration
</p>
<div className="mt-1 space-y-1">
<Link
href="/organization"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/organization")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<Building2 className="h-4 w-4" />
Organization
</Link>
{isAdmin ? (
<Link
href="/gateways"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/gateways")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<Network className="h-4 w-4" />
Gateways
</Link>
) : null}
{isAdmin ? (
<Link
href="/agents"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-slate-700 transition",
pathname.startsWith("/agents")
? "bg-blue-100 text-blue-800 font-medium"
: "hover:bg-slate-100",
)}
>
<Bot className="h-4 w-4" />
Agents
</Link>
) : null}
</div>
</div>
</nav>
</div>
<div className="border-t border-slate-200 p-4">
<div className="flex items-center gap-2 text-xs text-slate-500">
<span
className={cn(
"h-2 w-2 rounded-full",
systemStatus === "operational" && "bg-emerald-500",
systemStatus === "degraded" && "bg-rose-500",
systemStatus === "unknown" && "bg-slate-300",
)}
/>
{statusLabel}
</div>
</div>
</aside>
);
}