From 26f6b1d43c0fdc970048191f591a6bd9cc593c98 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 7 Jul 2026 17:13:52 -0700 Subject: [PATCH] =?UTF-8?q?app:=20centralize=20kind=E2=86=92icon=20in=20on?= =?UTF-8?q?e=20KIND=5FICONS=20map?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every surface hand-mapped deployment kind → lucide icon, so they could (and did) drift. Add KIND_ICONS/kindIcon to lib/labels beside kindLabel, and route KindBadge (→ all detail headers/cards/sections), the Overview tiles, and the program links through it. --- app/src/components/KindBadge.tsx | 6 ++++-- app/src/lib/labels.ts | 21 +++++++++++++++++++++ app/src/pages/Overview.tsx | 11 ++++++----- app/src/pages/ScheduledDetail.tsx | 7 +++++-- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/app/src/components/KindBadge.tsx b/app/src/components/KindBadge.tsx index b5b3db1..47d6cb8 100644 --- a/app/src/components/KindBadge.tsx +++ b/app/src/components/KindBadge.tsx @@ -1,5 +1,5 @@ import { cn } from "@/lib/utils" -import { KIND_DESCRIPTIONS, kindLabel } from "@/lib/labels" +import { KIND_DESCRIPTIONS, kindIcon, kindLabel } from "@/lib/labels" // Derived deployment kind → badge color. const kindColors: Record = { @@ -12,15 +12,17 @@ const kindColors: Record = { export function KindBadge({ kind }: { kind: string | null }) { if (!kind) return null + const Icon = kindIcon(kind) return ( + {kindLabel(kind)} ) diff --git a/app/src/lib/labels.ts b/app/src/lib/labels.ts index dc74666..76ebcd7 100644 --- a/app/src/lib/labels.ts +++ b/app/src/lib/labels.ts @@ -1,3 +1,24 @@ +import type { LucideIcon } from "lucide-react" +import { Box, Clock, LayoutTemplate, Package, Server, Waypoints, Wrench } from "lucide-react" + +// Canonical kind → icon — the single source of truth so the nav, Overview tiles, +// cards, the System map, and the command palette all speak one visual language. +// (Colors live in KindBadge; labels/descriptions are below.) `program` is the +// catalog pseudo-kind, not a deployment kind — the same Package glyph the +// Programs nav entry and Overview tile use. +export const KIND_ICONS: Record = { + service: Server, + job: Clock, + tool: Wrench, + static: LayoutTemplate, + reference: Waypoints, + program: Package, +} + +export function kindIcon(kind: string): LucideIcon { + return KIND_ICONS[kind] ?? Box +} + export const LAUNCHER_LABELS: Record = { python: "Python", command: "Command", diff --git a/app/src/pages/Overview.tsx b/app/src/pages/Overview.tsx index 30d2d9b..4a3c7c5 100644 --- a/app/src/pages/Overview.tsx +++ b/app/src/pages/Overview.tsx @@ -1,5 +1,6 @@ import { Link } from "react-router-dom" -import { Clock, Globe, Package, Server, Share2, Wrench } from "lucide-react" +import { Globe, Share2 } from "lucide-react" +import { KIND_ICONS } from "@/lib/labels" import { useGateway, useJobs, @@ -33,28 +34,28 @@ export function Overview() { const tiles = [ { to: "/services", - icon: Server, + icon: KIND_ICONS.service, label: "Services", value: services?.length ?? 0, detail: services ? `${upCount(serviceIds)} up` : "", }, { to: "/scheduled", - icon: Clock, + icon: KIND_ICONS.job, label: "Scheduled", value: jobs?.length ?? 0, detail: jobs ? `${jobs.length === 1 ? "job" : "jobs"}` : "", }, { to: "/tools", - icon: Wrench, + icon: KIND_ICONS.tool, label: "Tools", value: tools?.length ?? 0, detail: tools ? "on PATH" : "", }, { to: "/programs", - icon: Package, + icon: KIND_ICONS.program, label: "Programs", value: programs?.length ?? 0, detail: programs ? "in catalog" : "", diff --git a/app/src/pages/ScheduledDetail.tsx b/app/src/pages/ScheduledDetail.tsx index b2c60a0..44f3959 100644 --- a/app/src/pages/ScheduledDetail.tsx +++ b/app/src/pages/ScheduledDetail.tsx @@ -1,5 +1,6 @@ import { useParams, Link } from "react-router-dom" -import { Clock, Package } from "lucide-react" +import { Clock } from "lucide-react" +import { kindIcon } from "@/lib/labels" import { useJob } from "@/services/api/hooks" import { LogViewer } from "@/components/LogViewer" import { DetailHeader } from "@/components/detail/DetailHeader" @@ -8,6 +9,8 @@ import { SystemdPanel } from "@/components/detail/SystemdPanel" import { ConfigPanel } from "@/components/detail/ConfigPanel" import { RelatedDeployments } from "@/components/detail/RelatedDeployments" +const ProgramIcon = kindIcon("program") + export function ScheduledDetailPage() { const { name } = useParams<{ name: string }>() const { data: deployment, isLoading, error, refetch } = useJob(name ?? "") @@ -58,7 +61,7 @@ export function ScheduledDetailPage() { to={`/programs/${deployment.program}`} className="flex items-center gap-1.5 min-w-0 text-[var(--primary)] hover:underline" > - {deployment.program} + {deployment.program} )}