/** * @file The compact lane tile used in the Workspace's horizontal lane strip. * It carries only what you need to pick a lane — which lane, is it alive, * what stage — because the full card, its controls and its working-copy facts * live in the detail panel below it. Stage badges ride on the id row rather * than a line of their own, and progress (bar and percent) is deliberately * absent: the detail panel's pipeline map below shows the same thing with the * stage names attached. Keeping the tile small and fixed-width is what lets * many lanes stay scannable in one scrolling row. * @author Nguyễn Ngọc Trí Vĩ */ import { useTranslation } from "react-i18next"; import type { Lane } from "../../lib/types"; const LIVENESS_DOT: Record = { active: "bg-status-success", idle: "bg-surface-4", dead: "bg-status-danger", }; /** * Whether the inferred stage sits ahead of the declared one in node order. * * The declaration is located by the node the server resolved it onto (`state * === "current"`), not by `indexOf(lane.stage)`: a stage declared under an * ALIAS (`tests`, `booting`, `ship` — most of what the ship-feature skill * declares) is not a node id, so indexOf answers -1 and a detection sitting * well BEHIND the declaration would still be badged as the live one. * * `>=`, not `>`: an undeclared lane is rendered AT its detected node by the * server (see `inferredDisplayStage`), so the detection and the "current" node * are the same one — and that lane is precisely the one whose stage the badge * is the only readout for. A declared lane can never tie, because * recordDetection refuses any detection that isn't strictly ahead. */ function detectionLeads(lane: Lane): boolean { if (!lane.detected_stage) return false; const nodes = lane.pipeline_nodes; return ( nodes.findIndex((n) => n.id === lane.detected_stage) >= nodes.findIndex((n) => n.state === "current") ); } export default function LaneStripCard({ lane, selected, onSelect, }: { lane: Lane; selected: boolean; onSelect: () => void; }) { const { t } = useTranslation(["lanes"]); return ( ); }