Bug bash 2: 11 bugs in Stacks, Alerts, Docker, skins and the installer, fixed and verified (BUGS.md)

Stacks: deploy with every compose file (labels from inspect, not comma-joined ps);
refuse a stale overwrite; empty list without Docker. Alerts: firing state survives a
restart without re-announcing; vanished alerts are recorded as cleared with the reason;
rule values validated; 200 rules. Docker: 404 for a removed container's logs. Skins: four
palettes lifted to readable contrast. Phone: bigger toggles and swatches. Installer:
deploy republishes; an older published build is never installed silently.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-19 15:59:51 -07:00
co-authored by Claude Fable 5.1
parent 9c4f9dfa9f
commit eddba4250b
10 changed files with 320 additions and 68 deletions
+3 -3
View File
@@ -103,7 +103,7 @@ export interface SmartAttr { id: number; name: string; value: number; worst: num
export interface SmartInfo { device: string; available: boolean; supported: boolean; standby: boolean; passed: boolean | null; temp: number; power_on_hours: number; power_cycles: number; model?: string; serial?: string; firmware?: string; attrs: SmartAttr[]; nvme?: { critical_warning: number; percentage_used: number; available_spare: number; spare_threshold: number; media_errors: number; error_log_entries: number; data_read_bytes: number; data_written_bytes: number; unsafe_shutdowns: number }; mmc?: { life_a: number; life_b: number; pre_eol: number }; self_test?: string; self_test_remaining?: number; self_test_supported: boolean; self_test_note?: string; warnings: string[]; error?: string; fetched_at: number }
export interface DockerContainer { id: string; name: string; image: string; state: string; status: string; health: string; ports: string; stack: string; service: string; created: string; mem: number }
export interface DockerInfo { available: boolean; message?: string; tool?: string; containers: DockerContainer[]; images: Record<string, unknown>[]; volumes: Record<string, unknown>[]; networks: Record<string, unknown>[] }
export interface Stack { name: string; containers: string[]; running: number; file: string; host_file: string; via: string; editable: boolean; note?: string; has_env: boolean }
export interface Stack { name: string; containers: string[]; running: number; file: string; host_file: string; files: string[]; host_files: string[] | null; via: string; editable: boolean; note?: string; has_env: boolean }
export interface AlertRule { id: string; name: string; sensor: string; op: string; value: number | boolean | string; for_sec: number; severity: 'info' | 'warn' | 'crit'; enabled: boolean; machines: string }
export interface AlertChannel { type: 'ntfy' | 'webhook'; url: string }
export interface AlertEvent { t: number; kind: 'firing' | 'resolved'; rule: string; rule_id: string; machine: string; sensor: string; value: unknown; severity: string }
@@ -194,8 +194,8 @@ export const api = {
dockerLogs: (id: string, since = '') => req<{ lines: { t: string; m: string }[] }>('GET', `/api/docker/containers/${encodeURIComponent(id)}/logs${since ? `?since=${encodeURIComponent(since)}` : '?n=300'}`),
dockerInspect: (id: string) => req<Record<string, unknown>>('GET', `/api/docker/containers/${encodeURIComponent(id)}/inspect`),
stacks: () => req<{ stacks: Stack[] }>('GET', '/api/docker/stacks'),
stackFile: (name: string) => req<{ stack: Stack; text: string }>('GET', `/api/docker/stacks/${encodeURIComponent(name)}`),
saveStack: (name: string, text: string) => req<void>('PUT', `/api/docker/stacks/${encodeURIComponent(name)}`, { text }),
stackFile: (name: string, file = 0) => req<{ stack: Stack; text: string; sum: string }>('GET', `/api/docker/stacks/${encodeURIComponent(name)}?file=${file}`),
saveStack: (name: string, file: number, text: string, sum: string) => req<void>('PUT', `/api/docker/stacks/${encodeURIComponent(name)}?file=${file}`, { text, sum }),
stackAction: (name: string, action: 'deploy' | 'update' | 'restart' | 'stop') => req<TaskInfo>('POST', `/api/docker/stacks/${encodeURIComponent(name)}/${action}`),
alerts: () => req<AlertsInfo>('GET', '/api/alerts', undefined, true),
saveAlerts: (p: { rules?: AlertRule[]; channels?: AlertChannel[] }) => req<void>('PUT', '/api/alerts', p, true),