feat(sidebar): surface partial status for multi-container stacks (#1426)

Bulk stack-status aggregation collapsed a stack to "running" as soon as any
container was up, so a multi-container stack with crashed containers showed a
green UP pill and the degradation was invisible from the sidebar.

Add a crash-aware "partial" state: a stack is partial when at least one
container is running and at least one has genuinely failed (exited with a
non-zero code, dead, or crash-looping). Cleanly finished one-shot containers
(exit 0) and clean restart-policy cycling do not count, so an app with a
completed init job stays UP. The exit code is read from the container Status
string, so no extra inspect calls are needed.

Render partial as an amber PT pill with a hover tooltip showing the
running/total count, fold it into the Down filter (needs-attention), and treat
it as running for context-menu lifecycle actions so operators keep
stop/restart/update. The dashboard stack-health table, cross-node search rows,
and the command palette all pick up the new state through the shared status
surfaces.
This commit is contained in:
Anso
2026-06-24 19:57:49 -04:00
committed by GitHub
parent 2eafee3594
commit bb4ddde35a
22 changed files with 423 additions and 40 deletions
+12 -3
View File
@@ -13,6 +13,9 @@ interface StackRowProps {
file: string;
displayName: string;
status: StackRowStatus;
// Running/total container counts (set for any stack with containers); consumed only for the partial-stack pill tooltip.
running?: number;
total?: number;
isBusy: boolean;
isActive: boolean;
labels: Label[];
@@ -43,7 +46,7 @@ const MAX_VISIBLE_LABELS = 3;
export function StackRow(props: StackRowProps) {
const {
file, displayName, status, isBusy, isActive, labels,
file, displayName, status, running, total, isBusy, isActive, labels,
hasUpdate, hasGitPending, onSelect, kebabSlot,
bulkMode = false, isSelected = false, onToggleSelect,
} = props;
@@ -88,9 +91,15 @@ export function StackRow(props: StackRowProps) {
)}
</span>
{/* Status pill */}
{/* Status pill. Partial stacks add a hover tooltip with the running/total count. */}
<span className={cn('font-mono text-[10px] shrink-0 w-[22px] flex items-center', statusColor(status, isBusy))}>
{isBusy ? <Loader2 className="w-3 h-3 animate-spin" strokeWidth={2} /> : statusText(status)}
{isBusy ? (
<Loader2 className="w-3 h-3 animate-spin" strokeWidth={2} />
) : status === 'partial' && running !== undefined && total !== undefined ? (
<RowTooltip trigger={<span>{statusText(status)}</span>} label={`${running}/${total} running`} />
) : (
statusText(status)
)}
</span>
{/* Stack name */}