feat(daemon): add serial console reader and UI tab for serial logs; add version propagation and CI/release workflows

This commit is contained in:
2026-01-09 14:34:51 +00:00
parent 5234411c9d
commit 6dd6ead1c9
8 changed files with 262 additions and 7 deletions

View File

@@ -249,6 +249,27 @@ export class UIServer {
background: var(--success);
color: white;
}
.tabs {
display: flex;
border-bottom: 1px solid var(--border);
margin-bottom: 12px;
}
.tab {
padding: 8px 16px;
cursor: pointer;
color: var(--text-dim);
border-bottom: 2px solid transparent;
margin-bottom: -1px;
font-size: 12px;
text-transform: uppercase;
}
.tab:hover { color: var(--text); }
.tab.active {
color: var(--accent);
border-bottom-color: var(--accent);
}
.tab-content { display: none; }
.tab-content.active { display: block; }
</style>
</head>
<body>
@@ -339,8 +360,16 @@ export class UIServer {
<div id="microphones-list"></div>
</div>
<div class="card" style="grid-column: 1 / -1;">
<h2>Logs</h2>
<div class="logs" id="logs"></div>
<div class="tabs">
<div class="tab active" onclick="switchTab('daemon')">Daemon Logs</div>
<div class="tab" onclick="switchTab('serial')">Serial Console</div>
</div>
<div id="daemon-tab" class="tab-content active">
<div class="logs" id="logs"></div>
</div>
<div id="serial-tab" class="tab-content">
<div class="logs" id="serial-logs"></div>
</div>
</div>
</div>
</div>
@@ -362,7 +391,20 @@ export class UIServer {
return mins + 'm';
}
let initialVersion = null;
function updateStatus(data) {
// Check for version change and reload if needed
if (data.version) {
if (initialVersion === null) {
initialVersion = data.version;
} else if (data.version !== initialVersion) {
console.log('Server version changed from ' + initialVersion + ' to ' + data.version + ', reloading...');
location.reload();
return;
}
}
// Services
document.getElementById('sway-status').className =
'status-dot ' + (data.sway ? 'running' : 'stopped');
@@ -471,7 +513,7 @@ export class UIServer {
}
}
// Logs
// Daemon Logs
if (data.logs) {
const logsEl = document.getElementById('logs');
logsEl.innerHTML = data.logs.map(l =>
@@ -479,6 +521,31 @@ export class UIServer {
).join('');
logsEl.scrollTop = logsEl.scrollHeight;
}
// Serial Logs
if (data.serialLogs) {
const serialEl = document.getElementById('serial-logs');
if (data.serialLogs.length === 0) {
serialEl.innerHTML = '<div style="color: var(--text-dim);">No serial data available</div>';
} else {
serialEl.innerHTML = data.serialLogs.map(l =>
'<div class="log-entry">' + l + '</div>'
).join('');
serialEl.scrollTop = serialEl.scrollHeight;
}
}
}
function switchTab(tab) {
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
if (tab === 'daemon') {
document.querySelector('.tab:first-child').classList.add('active');
document.getElementById('daemon-tab').classList.add('active');
} else {
document.querySelector('.tab:last-child').classList.add('active');
document.getElementById('serial-tab').classList.add('active');
}
}
function setControlStatus(msg, isError) {