import { Component, For, Show } from 'solid-js'; import type { DockerContainer, DockerHost, DockerService, DockerTask, } from '@/types/api'; import { Card } from '@/components/shared/Card'; export type DockerTreeSelection = | { type: 'host'; hostId: string; id: string } | { type: 'service'; hostId: string; id: string } | { type: 'task'; hostId: string; serviceKey: string; id: string } | { type: 'container'; hostId: string; id: string }; export interface DockerTreeTaskEntry { nodeId: string; task: DockerTask; } export interface DockerTreeServiceEntry { key: string; service: DockerService; tasks: DockerTreeTaskEntry[]; } export interface DockerTreeContainerEntry { nodeId: string; container: DockerContainer; } export interface DockerTreeHostEntry { host: DockerHost; hostId: string; containers: DockerContainer[]; services: DockerTreeServiceEntry[]; standaloneContainers: DockerTreeContainerEntry[]; } interface ExpandState { isExpanded: () => boolean; toggle: () => void; setExpanded: (value: boolean) => void; } interface DockerTreeProps { hosts: DockerTreeHostEntry[]; selected?: DockerTreeSelection | null; onSelect?: (selection: DockerTreeSelection) => void; getHostState: (hostId: string) => ExpandState; getServiceState: (serviceKey: string) => ExpandState; } export const DockerTree: Component = (props) => { const isNodeSelected = (node: DockerTreeSelection) => { const current = props.selected; if (!current) return false; return ( current.type === node.type && current.hostId === node.hostId && current.id === node.id ); }; const hostDisplayName = (host: DockerHost) => host.displayName || host.hostname || host.id || 'Unknown host'; const hostStatusVariant = (host: DockerHost) => { const status = host.status?.toLowerCase() ?? 'unknown'; if (status === 'online') { return 'bg-green-500'; } if ( status === 'offline' || status === 'error' || status === 'down' || status === 'unreachable' ) { return 'bg-red-500'; } return 'bg-yellow-500'; }; const taskStatusVariant = (task: DockerTask) => { const state = task.currentState?.toLowerCase() ?? ''; if (state === 'running') return 'bg-green-500'; if (state === 'failed' || state === 'error') return 'bg-red-500'; return 'bg-yellow-500'; }; const describeTaskLabel = (task: DockerTask) => { if (task.slot !== undefined && task.slot !== null) { return `${task.containerName || task.containerId || 'Task'}:${task.slot}`; } return task.containerName || task.containerId || task.id?.slice(0, 12) || 'Task'; }; return ( ); };