feat(dashboard): add status+graph views
This commit is contained in:
@@ -27,6 +27,13 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Views -->
|
||||
<div class="view-tabs">
|
||||
<button class="tab-btn active" id="tabCards" onclick="setView('cards')">Cards</button>
|
||||
<button class="tab-btn" id="tabGraph" onclick="setView('graph')">Graph</button>
|
||||
<button class="tab-btn" id="tabStatus" onclick="setView('status')">Status</button>
|
||||
</div>
|
||||
|
||||
<!-- New Engram -->
|
||||
<div class="new-engram">
|
||||
<textarea id="newContent" placeholder="Neues Engramm..."></textarea>
|
||||
@@ -37,6 +44,12 @@
|
||||
<!-- Cards -->
|
||||
<div class="cards" id="cards"></div>
|
||||
|
||||
<!-- Graph -->
|
||||
<div class="graph" id="graph" style="display:none;"></div>
|
||||
|
||||
<!-- Status -->
|
||||
<div class="status" id="status" style="display:none;"></div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="pagination" id="pagination">
|
||||
<button id="btnPrev" onclick="prevPage()">◀</button>
|
||||
@@ -67,6 +80,7 @@ let state = {
|
||||
filter: 'all',
|
||||
search: '',
|
||||
autoRefresh: true,
|
||||
view: 'cards',
|
||||
};
|
||||
|
||||
// ─── Fetch ──────────────────────────────────────────────────────────────────
|
||||
@@ -84,6 +98,21 @@ async function loadStats() {
|
||||
document.getElementById('statErrors').textContent = s.errors;
|
||||
}
|
||||
|
||||
function setView(view) {
|
||||
state.view = view;
|
||||
document.getElementById('tabCards').classList.toggle('active', view === 'cards');
|
||||
document.getElementById('tabGraph').classList.toggle('active', view === 'graph');
|
||||
document.getElementById('tabStatus').classList.toggle('active', view === 'status');
|
||||
|
||||
document.getElementById('cards').style.display = view === 'cards' ? '' : 'none';
|
||||
document.getElementById('pagination').style.display = view === 'cards' ? '' : 'none';
|
||||
document.getElementById('graph').style.display = view === 'graph' ? '' : 'none';
|
||||
document.getElementById('status').style.display = view === 'status' ? '' : 'none';
|
||||
|
||||
if (view === 'graph') loadGraph();
|
||||
if (view === 'status') loadStatus();
|
||||
}
|
||||
|
||||
async function loadCards() {
|
||||
let url = `/api/engrams?limit=${state.limit}&offset=${state.offset}`;
|
||||
if (state.search) url += `&search=${encodeURIComponent(state.search)}`;
|
||||
@@ -99,6 +128,70 @@ async function loadCards() {
|
||||
document.getElementById('btnNext').disabled = data.items.length < state.limit;
|
||||
}
|
||||
|
||||
async function loadStatus() {
|
||||
const [cfg, db, jobs, ins] = await Promise.all([
|
||||
api('/api/config'),
|
||||
api('/api/db_info'),
|
||||
api('/api/jobs'),
|
||||
api('/api/insights?limit=8'),
|
||||
]);
|
||||
|
||||
const el = document.getElementById('status');
|
||||
const jobsHtml = (jobs.items || []).map(j => `
|
||||
<div class="kv-row">
|
||||
<div class="kv-key">${j.unit}</div>
|
||||
<div class="kv-val">${j.error ? ('ERR: ' + j.error) : (j.active + '/' + j.sub)}</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
const topTags = (ins.top_tags || []).map(t => `<span class="pill">${t.key} (${t.count})</span>`).join(' ');
|
||||
const topHosts = (ins.top_hosts || []).map(t => `<span class="pill">${t.key} (${t.count})</span>`).join(' ');
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="panel">
|
||||
<div class="panel-title">Config</div>
|
||||
<div class="kv-row"><div class="kv-key">workspace</div><div class="kv-val">${cfg.workspace}</div></div>
|
||||
<div class="kv-row"><div class="kv-key">db</div><div class="kv-val">${db.db_path}</div></div>
|
||||
<div class="kv-row"><div class="kv-key">db mtime</div><div class="kv-val">${new Date(db.mtime).toLocaleString()}</div></div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-title">Jobs</div>
|
||||
${jobsHtml || '<div class="muted">Keine Daten</div>'}
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-title">Insights</div>
|
||||
<div class="kv-row"><div class="kv-key">pending</div><div class="kv-val">${ins.pending}</div></div>
|
||||
<div class="kv-row"><div class="kv-key">top tags</div><div class="kv-val">${topTags || '-'}</div></div>
|
||||
<div class="kv-row"><div class="kv-key">top hosts</div><div class="kv-val">${topHosts || '-'}</div></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
async function loadGraph() {
|
||||
const g = await api('/api/graph?limit_nodes=250');
|
||||
const nodes = g.nodes || [];
|
||||
const edges = g.edges || [];
|
||||
|
||||
const countByKind = nodes.reduce((acc, n) => {
|
||||
acc[n.kind] = (acc[n.kind] || 0) + 1;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const el = document.getElementById('graph');
|
||||
el.innerHTML = `
|
||||
<div class="panel">
|
||||
<div class="panel-title">Graph (lightweight)</div>
|
||||
<div class="kv-row"><div class="kv-key">nodes</div><div class="kv-val">${nodes.length} (${Object.entries(countByKind).map(([k,v])=>k+':'+v).join(', ')})</div></div>
|
||||
<div class="kv-row"><div class="kv-key">edges</div><div class="kv-val">${edges.length}</div></div>
|
||||
<div class="muted">Aktuell: Tag/Host Knoten + Engram-Links. Nächster Schritt: echte Tool↔API↔Endpoint Ontologie.</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-title">Beispiele</div>
|
||||
<div class="muted">Tip: öffne ein Engram-Detail und folge Links.</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderCards() {
|
||||
const el = document.getElementById('cards');
|
||||
el.innerHTML = state.items.map(item => `
|
||||
|
||||
Reference in New Issue
Block a user