Updates
CI / test (push) Successful in 58s
Release rolling / release (push) Successful in 6m56s

This commit is contained in:
Raven Scott
2026-07-18 20:17:34 -04:00
parent 52a1823469
commit 41f5476a60
10 changed files with 1470 additions and 90 deletions
+72 -36
View File
@@ -17,6 +17,7 @@ import {
applySettingsToDom,
} from './client/settings.js'
import { drawMultiChart, CHART_PALETTE, pushRing } from './ui/charts.js'
import { createMetricsDashboard } from './ui/dashboard.js'
const $ = (id) => document.getElementById(id)
@@ -63,6 +64,13 @@ const els = {
chartDetailTitle: $('chart-detail-title'),
chartDetailMeta: $('chart-detail-meta'),
chartDetailDims: $('chart-detail-dims'),
chartDetailPanel: $('chart-detail-panel'),
metricsToc: $('metrics-toc'),
metricsWall: $('metrics-wall'),
metricsPlay: $('metrics-play'),
metricsPresets: $('metrics-presets'),
metricsMeta: $('metrics-meta'),
metricsHover: $('metrics-hover'),
collapseSidebarBtn: $('collapse-sidebar-btn'),
settingReduceMotion: $('setting-reduce-motion'),
settingChartPoints: $('setting-chart-points'),
@@ -82,6 +90,23 @@ try {
// ignore
}
const metricsDashboard = createMetricsDashboard({
els: {
root: $('charts-view'),
toc: $('metrics-toc'),
wall: $('metrics-wall'),
search: $('chart-search'),
playBtn: $('metrics-play'),
presets: $('metrics-presets'),
meta: $('metrics-meta'),
hoverReadout: $('metrics-hover'),
},
getCatalog: () => chartCatalog,
queryData: (args) => manager.request(Methods.queryData, args),
getPoints: () => seriesMax(),
onSelectChart: (id) => selectCatalogChart(id),
})
/** @type {Record<string, number[]>} */
const series = {
cpu: [],
@@ -512,6 +537,7 @@ function onSamples(samples, conn) {
paint('chart-detail', [{ values: series.detail, color: CHART_PALETTE.cpuUser }])
}
}
metricsDashboard.onSamples(samples || [])
redrawAll()
}
@@ -529,7 +555,9 @@ function prependAnomaly(ev) {
li.style.cursor = 'pointer'
li.title = `Show ${ev.chart}`
li.addEventListener('click', () => {
showView('overview')
showView('charts')
metricsDashboard.scrollToChart(ev.chart)
selectCatalogChart(ev.chart).catch(() => {})
if ([...els.exploreChart.options].some((o) => o.value === ev.chart)) {
els.exploreChart.value = ev.chart
exploreChartId = ev.chart
@@ -596,42 +624,28 @@ function renderFleetStrip(fleet, desktopPeers) {
els.fleetStrip.classList.toggle('hidden', rows.length === 0)
}
function renderChartCatalog(filter = '') {
if (!els.chartCatalogList) return
const q = filter.trim().toLowerCase()
const ids = Object.keys(chartCatalog)
.filter((id) => !q || id.toLowerCase().includes(q))
.sort()
els.chartCatalogList.innerHTML = ''
if (!ids.length) {
const li = document.createElement('li')
li.className = 'muted'
li.textContent = manager.active ? 'No matching charts' : 'Connect an agent first'
els.chartCatalogList.appendChild(li)
return
}
for (const id of ids) {
const li = document.createElement('li')
li.textContent = id
if (id === selectedCatalogChart) li.classList.add('active')
li.addEventListener('click', () => selectCatalogChart(id))
els.chartCatalogList.appendChild(li)
}
function renderChartCatalog(_filter = '') {
metricsDashboard.render()
}
async function selectCatalogChart(id) {
selectedCatalogChart = id
series.detail = []
renderChartCatalog(els.chartSearch?.value || '')
const meta = chartCatalog[id] || {}
if (els.chartDetailTitle) els.chartDetailTitle.textContent = id
if (els.chartDetailPanel) els.chartDetailPanel.classList.remove('hidden')
if (els.chartDetailTitle) els.chartDetailTitle.textContent = meta.title || id
if (els.chartDetailMeta) {
els.chartDetailMeta.textContent = meta.family || meta.context || meta.units || ''
els.chartDetailMeta.textContent = [meta.context, meta.family, meta.units]
.filter(Boolean)
.join(' · ')
}
if (els.chartDetailDims) {
const dims = meta.dimensions || meta.labels || Object.keys(meta).slice(0, 12)
const dims = meta.dimensions || meta.labels || []
els.chartDetailDims.textContent = Array.isArray(dims)
? dims.join('\n')
? dims
.map((d) => (typeof d === 'string' ? d : d.id || d.name))
.filter(Boolean)
.join('\n')
: JSON.stringify(meta, null, 2)
}
try {
@@ -641,12 +655,34 @@ async function selectCatalogChart(id) {
points: seriesMax(),
})
series.detail = []
for (const row of q.data || []) {
pushPoint('detail', row[1] ?? 0)
/** @type {Array<{ values: number[], color: string, label: string }>} */
const lines = []
const labels = (q.labels || []).filter((l) => l && l !== 'time')
if (labels.length) {
for (let i = 0; i < labels.length; i++) {
const values = []
for (const row of q.data || []) values.push(Number(row[i + 1]) || 0)
lines.push({
values,
color: CHART_PALETTE.compare[i % CHART_PALETTE.compare.length],
label: labels[i],
})
if (i === 0) series.detail = values.slice()
}
paint('chart-detail', lines, {
stacked: String(meta.chartType || '').toLowerCase() === 'stacked',
showYAxis: true,
})
} else {
for (const row of q.data || []) pushPoint('detail', row[1] ?? 0)
paint('chart-detail', [{ values: series.detail, color: CHART_PALETTE.cpuUser }], {
showYAxis: true,
})
}
paint('chart-detail', [{ values: series.detail, color: CHART_PALETTE.cpuUser }])
} catch {
paint('chart-detail', [{ values: series.detail, color: CHART_PALETTE.cpuUser }])
paint('chart-detail', [{ values: series.detail, color: CHART_PALETTE.cpuUser }], {
showYAxis: true,
})
}
}
@@ -794,7 +830,10 @@ function showView(name) {
document.querySelectorAll('#main-nav .nav-link').forEach((btn) => {
btn.classList.toggle('active', btn.dataset.view === name)
})
if (name === 'charts') renderChartCatalog(els.chartSearch?.value || '')
if (name === 'charts') {
metricsDashboard.render()
requestAnimationFrame(() => metricsDashboard.redrawVisible())
}
if (name === 'settings') syncSettingsUi()
requestAnimationFrame(() => redrawAll())
}
@@ -866,6 +905,7 @@ els.settingChartPoints?.addEventListener('change', () => {
persist({ chartPoints: n })
els.settingChartPoints.value = String(n)
seedHistory().catch(() => redrawAll())
metricsDashboard.redrawVisible()
})
els.settingDefaultExplore?.addEventListener('change', () => {
@@ -889,10 +929,6 @@ els.btnRefreshMeta?.addEventListener('click', () => {
refreshMeta().catch((err) => log(`Refresh failed: ${err.message}`))
})
els.chartSearch?.addEventListener('input', () => {
renderChartCatalog(els.chartSearch.value)
})
/* ─── Connect / peers ─── */
els.btnConnect.addEventListener('click', async () => {
const raw = els.connectInput.value.trim()