import { useEffect, useMemo, useRef } from 'react' import type { Machine } from '@/types/api' export function getMachineTitle(machine: Machine): string { if (machine.metadata?.displayName) return machine.metadata.displayName if (machine.metadata?.host) return machine.metadata.host return machine.id.slice(0, 8) } const STORAGE_KEY = 'hapi-machine-labels' function isBrowser(): boolean { return typeof window !== 'undefined' && typeof document !== 'undefined' } function readCachedLabels(): Record { if (!isBrowser()) return {} try { const raw = localStorage.getItem(STORAGE_KEY) if (!raw) return {} const parsed: unknown = JSON.parse(raw) if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {} const labels: Record = {} for (const [key, value] of Object.entries(parsed)) { if (typeof value === 'string' && value.length > 0) { labels[key] = value } } return labels } catch { return {} } } function writeCachedLabels(labels: Record): void { if (!isBrowser()) return try { localStorage.setItem(STORAGE_KEY, JSON.stringify(labels)) } catch { // Ignore storage errors } } /** * Machine id → display label for the session list. Live data from the * machines query wins, but labels are also cached in localStorage so a * machine whose row is gone (reinstalled CLI, stale sessions) or whose * query has not loaded yet keeps its last known name instead of falling * back to a raw id prefix. */ export function useMachineLabels(machines: Machine[]): Record { const previousLabelsRef = useRef | null>(null) const labels = useMemo(() => { const merged = readCachedLabels() for (const machine of machines) { merged[machine.id] = getMachineTitle(machine) } const previous = previousLabelsRef.current if (previous) { const previousKeys = Object.keys(previous) const mergedKeys = Object.keys(merged) if ( previousKeys.length === mergedKeys.length && mergedKeys.every((key) => merged[key] === previous[key]) ) { return previous } } previousLabelsRef.current = merged return merged }, [machines]) useEffect(() => { writeCachedLabels(labels) }, [labels]) return labels }