From a5ebfdc9ce6d74f5c0c0f0ada3f014aa364a168d Mon Sep 17 00:00:00 2001 From: Mitchell-Johnson Date: Fri, 9 Oct 2026 22:28:00 -0700 Subject: [PATCH] VGA console: agree to spice-html5's binary subprotocol; label layout and two labels in the detail pane Co-Authored-By: Claude Fable 5.1 --- internal/api/virt.go | 3 ++- web/src/Virtualization.tsx | 4 ++-- web/src/styles.css | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/api/virt.go b/internal/api/virt.go index cc90c31..0d0dc1b 100644 --- a/internal/api/virt.go +++ b/internal/api/virt.go @@ -527,7 +527,8 @@ func (s *Server) virtVGA(w http.ResponseWriter, r *http.Request) { jsonErr(w, 400, "bad name") return } - conn, err := websocket.Accept(w, r, &websocket.AcceptOptions{CompressionMode: websocket.CompressionDisabled}) + // spice-html5 asks for the "binary" subprotocol and gives up unless the server agrees to it + conn, err := websocket.Accept(w, r, &websocket.AcceptOptions{CompressionMode: websocket.CompressionDisabled, Subprotocols: []string{"binary"}}) if err != nil { return } diff --git a/web/src/Virtualization.tsx b/web/src/Virtualization.tsx index 234dcdb..11ca41c 100644 --- a/web/src/Virtualization.tsx +++ b/web/src/Virtualization.tsx @@ -244,9 +244,9 @@ function Detail({ i, st, onBack, onChanged, onTask }: { i: VirtInstance; st: Vir
{i.name}{kind(i)}{i.status.toLowerCase()}
-
Image{i.image || '—'}{i.arch ? · {i.arch} : ''}
+
Image{i.image || (Object.keys(i.devices).some((d) => d.startsWith('iso')) ? 'none — installed from an ISO' : 'none')}{i.arch ? · {i.arch} : ''}
{i.description &&
About{i.description}
} - {running &&
Using{i.cpu_pct.toFixed(0)}% of a core · {fmtBytes(i.mem_usage)}{i.mem_peak ? ` (peak ${fmtBytes(i.mem_peak)})` : ''}{i.processes ? ` · ${i.processes} processes` : ''}
} + {running &&
Using{i.cpu_pct.toFixed(0)}% of a core · {fmtBytes(i.mem_usage)}{i.mem_peak ? ` (peak ${fmtBytes(i.mem_peak)})` : ''}{i.processes > 0 ? ` · ${i.processes} processes` : ''}
}
Limits{i.cpu ? `${i.cpu} CPU` : 'all CPUs'} · {i.memory || 'unlimited memory'}
{i.disk_total > 0 &&
Disk{fmtBytes(i.disk_usage)} of {fmtBytes(i.disk_total)}
}
Network{i.ipv4.length ? i.ipv4.join(' ') : running ? 'no address yet' : '—'}
diff --git a/web/src/styles.css b/web/src/styles.css index 756edd8..846d82f 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -900,7 +900,8 @@ pre.diff .add { color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, .virt-pick .svc-row { padding: 6px 10px; } .virt-kv { display: grid; grid-template-columns: max-content 1fr; gap: 2px 12px; font-size: 12px; word-break: break-all; } .virt-form-row { display: flex; gap: 8px; } -.virt-form-row > label { flex: 1; min-width: 0; } +.virt-form-row > label { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; } +.virt-form-row > label > input, .virt-form-row > label > select { width: 100%; box-sizing: border-box; } .virt .modal { max-width: 640px; } .vga-back { align-items: stretch; padding: 10px; } .vga { display: flex; flex-direction: column; gap: 6px; width: 100%; height: 100%; max-width: none; max-height: none; background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 8px; }