Updates
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user