Files
go-otel/otel-ui/src/components/layout/IconRail.tsx
T
mats 0ed2935f04
Build and Publish / Metadata (push) Successful in 8s
Build and Publish / BuildAndDeployAmd64 (push) Failing after 36s
alot more changes
2026-09-21 18:59:13 +02:00

131 lines
4.4 KiB
TypeScript

import React from "react"
import {
Activity,
AlertOctagon,
CloudCog,
Fingerprint,
GitBranch,
Globe,
LineChart,
Radar,
ScrollText,
TrendingUp,
Waypoints,
Wrench,
} from "lucide-react"
import type { LucideIcon } from "lucide-react"
import { useObservabilityData } from "../../hooks/useObservabilityData"
import { useIssues } from "../../hooks/useIssues"
import { useStatsAvailability } from "../../hooks/useStats"
interface RailItem {
tab: string
label: string
Icon: LucideIcon
dotTone?: "critical" | "warn"
dotVisible?: boolean
}
/**
* The 72px fixed icon rail: primary navigation for every screen. Icon-only
* with a real aria-label per control (spec: "72px icon rail, fixed. 46x46
* targets, aria-label on every one"). A small status dot only appears when
* that view has something real to flag (open issues, error logs) - it is
* never decorative.
*/
export const IconRail: React.FC = () => {
const { activeTab, setActiveTab, logs } = useObservabilityData()
const { issues } = useIssues()
const statsAvailable = useStatsAvailability()
const openIssuesCount = React.useMemo(
() => issues.filter((i) => !i.status || i.status === "open").length,
[issues],
)
const errorLogCount = React.useMemo(() => {
let errs = 0
logs.forEach((log) => {
;(log.scopeLogs ?? []).forEach((sl) => {
;(sl.logRecords ?? []).forEach((r) => {
if ((r.severityNumber ?? 0) >= 17) errs += 1
})
})
})
return errs
}, [logs])
const items: RailItem[] = [
{ tab: "tab0", label: "Triage overview", Icon: AlertOctagon, dotTone: "critical", dotVisible: openIssuesCount > 0 },
{ tab: "tab8", label: "Similarity patterns", Icon: GitBranch },
{ tab: "tab9", label: "Cluster rollouts", Icon: CloudCog },
{ tab: "tab1", label: "Traces & spans", Icon: Activity },
{ tab: "tab3", label: "Live log stream", Icon: ScrollText, dotTone: "warn", dotVisible: errorLogCount > 0 },
{ tab: "tab2", label: "Metrics & APM", Icon: LineChart },
{ tab: "tab7", label: "RUM sessions", Icon: Globe },
{ tab: "tab10", label: "Source IPs", Icon: Fingerprint },
...(statsAvailable ? [{ tab: "tab5", label: "Historical trends", Icon: TrendingUp }] : []),
{ tab: "tab6", label: "Archive & trap", Icon: Radar },
]
return (
<nav
aria-label="Primary"
className="fixed left-0 top-0 z-50 flex h-full w-[72px] flex-col items-center gap-1.5 border-r border-ds-line bg-ds-chrome py-4"
>
<button
type="button"
onClick={() => setActiveTab("tab0")}
aria-label="Ohhtel — go to triage overview"
className="mb-2 flex h-[34px] w-[34px] items-center justify-center rounded-[10px] bg-ds-accent-bg text-ds-accent"
>
<Waypoints className="h-[19px] w-[19px]" aria-hidden="true" />
</button>
{items.map((item) => {
const isActive = activeTab === item.tab
return (
<button
key={item.tab}
type="button"
onClick={() => setActiveTab(item.tab)}
aria-label={item.label}
aria-current={isActive ? "page" : undefined}
title={item.label}
className={`relative flex h-[46px] w-[46px] items-center justify-center rounded-xl transition-colors ${
isActive ? "bg-ds-surface-2 text-ds-text" : "text-ds-text-3 hover:bg-ds-surface-2 hover:text-ds-text-2"
}`}
>
<item.Icon className="h-5 w-5" aria-hidden="true" />
{item.dotVisible && (
<span
aria-hidden="true"
className={`absolute right-2 top-2 h-[7px] w-[7px] rounded-full ${
item.dotTone === "critical" ? "bg-ds-critical" : "bg-ds-warn"
}`}
/>
)}
</button>
)
})}
<span className="flex-grow" />
<button
type="button"
onClick={() => setActiveTab("tab4")}
aria-label="Setup & agent API"
aria-current={activeTab === "tab4" ? "page" : undefined}
title="Setup & agent API"
className={`flex h-[46px] w-[46px] items-center justify-center rounded-xl transition-colors ${
activeTab === "tab4" ? "bg-ds-surface-2 text-ds-text" : "text-ds-text-3 hover:bg-ds-surface-2 hover:text-ds-text-2"
}`}
>
<Wrench className="h-5 w-5" aria-hidden="true" />
</button>
</nav>
)
}
export default IconRail