Files
portal/docs/observer/dashboard.js
T

75 lines
2.7 KiB
JavaScript

import { parseEpisodes } from './dashboard-core.js';
const AGD = window.AGD;
let episodes = [];
let skipped = 0;
let network = null;
// ── data loading ──────────────────────────────────────────────
async function loadEpisodes() {
const files = await fetch('/api/episodes').then((r) => r.json());
const all = [];
let skip = 0;
for (const f of files) {
const url = '/docs/observer/' + f;
const text = await fetch(url).then((r) => (r.ok ? r.text() : ''));
const r = parseEpisodes(text);
all.push(...r.episodes);
skip += r.skipped;
}
all.sort((a, b) => String(a.startedAt).localeCompare(String(b.startedAt)));
episodes = all;
skipped = skip;
document.getElementById('status').textContent =
`${episodes.length} эпизодов · ${skipped} пропущено`;
}
// ── graph banner ──────────────────────────────────────────────
function renderGraph() {
const nodes = new vis.DataSet(AGD.NODES);
const edges = new vis.DataSet(AGD.EDGES);
network = new vis.Network(
document.getElementById('network'),
{ nodes, edges },
{
groups: AGD.GROUPS,
nodes: { shape: 'dot', borderWidth: 2, font: { multi: 'html' } },
edges: { smooth: { type: 'continuous', roundness: 0.5 } },
physics: { enabled: false },
interaction: { hover: true, tooltipDelay: 400 },
}
);
network.once('afterDrawing', () => network.fit());
return { nodes, edges };
}
// ── view switching ────────────────────────────────────────────
const views = {};
let activeView = 'map';
function switchView(name) {
activeView = name;
for (const v of ['map', 'replay', 'feed', 'aggregate']) {
document.getElementById('view-' + v).style.display = v === name ? 'block' : 'none';
}
document.querySelectorAll('#tabbar button').forEach((b) => {
b.classList.toggle('active', b.dataset.view === name);
});
if (views[name]) views[name]();
}
// ── boot ──────────────────────────────────────────────────────
async function boot() {
const gds = renderGraph();
window.__graph = { network, ...gds };
document.querySelectorAll('#tabbar button').forEach((b) => {
b.addEventListener('click', () => switchView(b.dataset.view));
});
await loadEpisodes();
switchView('map');
}
export function getEpisodes() { return episodes; }
export { views, switchView };
boot();