feat(web-ui): add Node column to Containers screen + integrated log viewer

This commit is contained in:
Wild Dragon Dev 2026-06-04 01:48:44 +00:00
parent 2f13c8d8b1
commit df6ca084ff

View file

@ -1056,7 +1056,12 @@ function Containers() {
const logsModal = logsModalState; const logsModal = logsModalState;
const setLogsModal = setLogsModalState; const setLogsModal = setLogsModalState;
const showLogs = (c) => setLogsModal(c); const showLogs = (c) => {
setLogsModal({ ...c, logs: null }); // Show loading state
window.ZAMPP_API.fetch(`/cluster/containers/${c.node_id}/${c.id}/logs`)
.then(d => setLogsModal(p => ({ ...p, logs: d.logs || '(no logs)' })))
.catch(e => setLogsModal(p => ({ ...p, logs: `Error: ${e.message}` })));
};
const restartContainer = async (c) => { const restartContainer = async (c) => {
if (!(await confirm({ title: 'Restart container?', message: 'Restart container "' + c.name + '"?\nIn-flight requests will be dropped.', confirmLabel: 'Restart' }))) return; if (!(await confirm({ title: 'Restart container?', message: 'Restart container "' + c.name + '"?\nIn-flight requests will be dropped.', confirmLabel: 'Restart' }))) return;
@ -1114,16 +1119,9 @@ function Containers() {
<button className="icon-btn" aria-label="Close" onClick={() => setLogsModal(null)}><Icon name="x" /></button> <button className="icon-btn" aria-label="Close" onClick={() => setLogsModal(null)}><Icon name="x" /></button>
</div> </div>
<div className="modal-body"> <div className="modal-body">
<div style={{ fontSize: 12, color: 'var(--text-3)', marginBottom: 8 }}> <pre className="mono" style={{ display: 'block', background: 'var(--bg-2)', padding: 10, borderRadius: 5, fontSize: 11, overflow: 'auto', maxHeight: 400, whiteSpace: 'pre-wrap' }}>
Live log streaming over the websocket isn't wired yet. SSH to the host that runs this container and tail the logs directly: {logsModal.logs || 'Loading logs…'}
</div> </pre>
<code className="mono" style={{ display: 'block', background: 'var(--bg-2)', padding: 10, borderRadius: 5, fontSize: 11.5, overflowX: 'auto' }}>
docker compose logs -f {logsModal.name}
</code>
<div style={{ fontSize: 11.5, color: 'var(--text-3)', marginTop: 10 }}>
Or grab the last 200 lines:&nbsp;
<span className="mono">docker logs --tail 200 {logsModal.name}</span>
</div>
</div> </div>
<div className="modal-foot"> <div className="modal-foot">
<button className="btn ghost sm" onClick={() => { <button className="btn ghost sm" onClick={() => {
@ -1148,6 +1146,7 @@ function Containers() {
{containers !== null && containers.length > 0 && ( {containers !== null && containers.length > 0 && (
<div className="panel"> <div className="panel">
<div className="container-row head"> <div className="container-row head">
<div>Node</div>
<div>Container</div> <div>Container</div>
<div>Image</div> <div>Image</div>
<div>State</div> <div>State</div>
@ -1158,6 +1157,7 @@ function Containers() {
</div> </div>
{containers.map(c => ( {containers.map(c => (
<div key={c.id || c.name} className="container-row"> <div key={c.id || c.name} className="container-row">
<div style={{ fontWeight: 500, fontSize: 13 }}>{c.node_hostname}</div>
<div> <div>
<div style={{ fontWeight: 500, fontSize: 13 }}>{c.name}</div> <div style={{ fontWeight: 500, fontSize: 13 }}>{c.name}</div>
<div className="mono" style={{ fontSize: 11, color: "var(--text-3)" }}>up {c.uptime}</div> <div className="mono" style={{ fontSize: 11, color: "var(--text-3)" }}>up {c.uptime}</div>