SysOps: deploy-all — 2026-06-09 11:27 UTC

This commit is contained in:
sysops
2026-06-09 11:27:49 +00:00
parent 7f973b7203
commit 9b88e7c110
4 changed files with 357 additions and 32 deletions
+80 -16
View File
@@ -2,7 +2,7 @@
{% block extra_head %}
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
<link rel="stylesheet" href="/static/css/hermes.css" />
<link rel="stylesheet" href="/static/css/herman-dashboard.css?v=14" />
<link rel="stylesheet" href="/static/css/herman-dashboard.css?v=15" />
{% endblock %}
{% block content %}
<div class="herman-shell hm-neo">
@@ -24,11 +24,6 @@
</div>
<section class="panel herman-briefing" x-data="dashboardBriefing()" x-init="init()">
<div class="briefing-loading-overlay" x-show="loading" x-cloak>
<div class="loading-dots"><span></span><span></span><span></span></div>
<p x-text="loadingMsg"></p>
</div>
<header class="herman-briefing-header">
<div>
<h2>Dagelijkse briefing</h2>
@@ -44,6 +39,24 @@
</div>
</header>
<div id="hm-live-bar" class="hm-live-bar" x-show="loading || liveLog.length" x-cloak :class="loading ? 'hm-live-bar-active' : 'hm-live-bar-done'">
<div class="hm-live-bar-head">
<span class="hm-live-dot"></span>
<strong class="hm-live-title" x-text="loading ? loadingMsg : 'Dagrapport voltooid'"></strong>
<span class="hm-live-progress" x-show="loading" x-text="liveProgress"></span>
<button type="button" class="btn btn-sm hm-live-close" x-show="!loading && liveLog.length" @click="liveLog = []"></button>
</div>
<ol id="hm-live-log" class="hm-live-log">
<template x-for="(entry, idx) in liveLog" :key="idx">
<li :class="'hm-live-entry hm-live-' + (entry.status || 'ok') + (entry.type === 'agent_msg' ? ' hm-live-agent' : '')">
<span class="hm-live-src" x-text="entry.source || entry.agent"></span>
<span class="hm-live-msg" x-text="entry.message"></span>
<small class="hm-live-detail" x-show="entry.detail" x-text="entry.detail"></small>
</li>
</template>
</ol>
</div>
<div id="viz-toolbar" class="viz-toolbar"></div>
<div id="dashboard-customize" class="hm-customize-wrap" x-show="editLayout" x-cloak></div>
@@ -190,7 +203,8 @@
const INITIAL_BRIEFING = {{ briefing_payload | tojson }};
function dashboardBriefing() {
return {
loading: false, loadingMsg: 'Herman werkt…', editLayout: false,
loading: false, loadingMsg: 'Herman werkt…', liveLog: [], liveProgress: '',
editLayout: false,
content: INITIAL_BRIEFING.content || '', createdAt: INITIAL_BRIEFING.created_at || '',
_pollStop: null, _wsStop: null, _vizMode: 'neo-bars', _stats: null,
_prefs: null, _setDragMode: null, _saveTimer: null,
@@ -359,20 +373,70 @@ function dashboardBriefing() {
if (toast !== false) Cockpit.toast('Live data bijgewerkt', 'success');
} catch (e) { if (toast !== false) Cockpit.toast(e.message, 'error'); }
},
pushLiveEntry(entry) {
this.liveLog.push(entry);
this.loadingMsg = entry.message || this.loadingMsg;
if (entry.type === 'step') {
const done = this.liveLog.filter(e => e.type === 'step' && e.status === 'ok').length;
this.liveProgress = done + ' bronnen geladen';
}
this.$nextTick(() => {
const log = document.getElementById('hm-live-log');
if (log) log.scrollTop = log.scrollHeight;
const bar = document.getElementById('hm-live-bar');
if (bar && this.loading) bar.scrollIntoView({ behavior: 'smooth', block: 'start' });
});
},
async generate() {
this.loading = true;
this.loadingMsg = 'Live data laden…';
await this.refreshLive(false);
this.loadingMsg = 'Herman schrijft dagrapport…';
this.liveLog = [];
this.liveProgress = '';
this.loadingMsg = 'Herman start dagrapport…';
window.scrollTo({ top: 0, behavior: 'smooth' });
const bar = document.getElementById('hm-live-bar');
if (bar) bar.scrollIntoView({ behavior: 'smooth', block: 'start' });
try {
const r = await Cockpit.api('/api/herman/briefing', { method: 'POST' });
this.content = r.content || '';
this.createdAt = r.generated_at || new Date().toISOString();
BriefingCharts.render(document.getElementById('briefing-dashboard'), r.stats, r.content, this.createdAt, this._vizMode);
this.renderClientsMini(r.stats || {});
const resp = await fetch('/api/herman/briefing/stream', { method: 'POST' });
if (!resp.ok) throw new Error('Stream mislukt (' + resp.status + ')');
const reader = resp.body.getReader();
const decoder = new TextDecoder();
let buf = '';
let result = null;
while (true) {
const { done, value } = await reader.read();
if (done) break;
buf += decoder.decode(value, { stream: true });
const parts = buf.split('\n\n');
buf = parts.pop() || '';
for (const chunk of parts) {
const line = chunk.trim();
if (!line.startsWith('data:')) continue;
const evt = JSON.parse(line.replace(/^data:\s*/, ''));
if (evt.type === 'step' || evt.type === 'agent_msg') {
this.pushLiveEntry(evt);
} else if (evt.type === 'done') {
result = evt;
this.pushLiveEntry({ type: 'step', status: 'ok', source: 'Herman', message: '✓ Dagrapport klaar!' });
} else if (evt.type === 'error') {
throw new Error(evt.message || 'Onbekende fout');
}
}
}
if (!result) throw new Error('Geen resultaat van Herman');
this.content = result.content || '';
this.createdAt = result.generated_at || new Date().toISOString();
this._stats = result.stats;
BriefingCharts.render(document.getElementById('briefing-dashboard'), result.stats, result.content, this.createdAt, this._vizMode);
this.renderClientsMini(result.stats || {});
this.renderActivityLog((result.stats || {}).activity_log || []);
document.getElementById('briefing-meta').textContent = 'Rapport: ' + this.createdAt.substring(0, 19).replace('T', ' ') + ' UTC';
Cockpit.toast('Dagrapport klaar!', 'success');
} catch (e) { Cockpit.toast(e.message, 'error'); }
} catch (e) {
this.pushLiveEntry({ type: 'step', status: 'warn', source: 'Fout', message: e.message || String(e) });
Cockpit.toast(e.message || 'Fout bij genereren', 'error');
}
this.loading = false;
this.loadingMsg = 'Klaar';
}
};
}