better metrics (dashboard and show no sessions in metrics page if nothing is running for active sessions donut graph)
This commit is contained in:
@@ -97,6 +97,19 @@ function formatWeekLabel(timestamp) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function compactRepeatedTickLabel(value, index, ticks) {
|
||||||
|
const labelFor = (tickValue) => {
|
||||||
|
const labels = this?.chart?.data?.labels || [];
|
||||||
|
return labels[Number(tickValue)] ?? this?.getLabelForValue?.(tickValue) ?? "";
|
||||||
|
};
|
||||||
|
const labels = (ticks || []).map((tick) => labelFor(tick.value));
|
||||||
|
const current = labels[index] || labelFor(value);
|
||||||
|
if (!current) return "";
|
||||||
|
const isRunStart = index === 0 || labels[index - 1] !== current;
|
||||||
|
const isRunEnd = index === labels.length - 1 || labels[index + 1] !== current;
|
||||||
|
return isRunStart || isRunEnd ? current : "";
|
||||||
|
}
|
||||||
|
|
||||||
function aggregateOnlineHistory(history, snapshot) {
|
function aggregateOnlineHistory(history, snapshot) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const weekAgo = now - 7 * 24 * 60 * 60 * 1000;
|
const weekAgo = now - 7 * 24 * 60 * 60 * 1000;
|
||||||
@@ -227,7 +240,12 @@ function makeCharts() {
|
|||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: {
|
||||||
grid: { display: false },
|
grid: { display: false },
|
||||||
ticks: { color: palette.muted, maxRotation: 0, maxTicksLimit: 5 },
|
ticks: {
|
||||||
|
color: palette.muted,
|
||||||
|
maxRotation: 0,
|
||||||
|
maxTicksLimit: 5,
|
||||||
|
callback: compactRepeatedTickLabel,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
y: {
|
y: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ let latestByCountry = {};
|
|||||||
const GEOJSON_URL = "/vendor/geo-countries/countries.geojson";
|
const GEOJSON_URL = "/vendor/geo-countries/countries.geojson";
|
||||||
const MAX_CHART_POINTS = 240;
|
const MAX_CHART_POINTS = 240;
|
||||||
const METRICS_POLL_INTERVAL_MS = 5000;
|
const METRICS_POLL_INTERVAL_MS = 5000;
|
||||||
|
const SESSION_LABELS = ["Console", "Remote Desktop", "Files", "Processes"];
|
||||||
|
const SESSION_COLORS = ["#34d399", "#c084fc", "#60a5fa", "#fb923c"];
|
||||||
|
const SESSION_EMPTY_COLOR = "rgba(100, 116, 139, 0.35)";
|
||||||
|
|
||||||
if (typeof Chart !== "undefined") {
|
if (typeof Chart !== "undefined") {
|
||||||
Chart.defaults.color = "#cbd5e1";
|
Chart.defaults.color = "#cbd5e1";
|
||||||
@@ -76,6 +79,34 @@ function makeLineChart(canvas, datasets, options = {}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSessionValues(sessions = {}) {
|
||||||
|
return [
|
||||||
|
Number(sessions.console) || 0,
|
||||||
|
Number(sessions.remoteDesktop) || 0,
|
||||||
|
Number(sessions.fileBrowser) || 0,
|
||||||
|
Number(sessions.process) || 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSessionsChart(sessions = {}) {
|
||||||
|
if (!sessionsChart) return;
|
||||||
|
const values = getSessionValues(sessions);
|
||||||
|
const total = values.reduce((sum, value) => sum + value, 0);
|
||||||
|
const dataset = sessionsChart.data.datasets[0];
|
||||||
|
if (total > 0) {
|
||||||
|
sessionsChart.data.labels = SESSION_LABELS;
|
||||||
|
dataset.data = values;
|
||||||
|
dataset.backgroundColor = SESSION_COLORS;
|
||||||
|
sessionsChart.options.plugins.legend.display = true;
|
||||||
|
} else {
|
||||||
|
sessionsChart.data.labels = ["No active sessions"];
|
||||||
|
dataset.data = [1];
|
||||||
|
dataset.backgroundColor = [SESSION_EMPTY_COLOR];
|
||||||
|
sessionsChart.options.plugins.legend.display = false;
|
||||||
|
}
|
||||||
|
sessionsChart.update("none");
|
||||||
|
}
|
||||||
|
|
||||||
function initCharts() {
|
function initCharts() {
|
||||||
const clientsCtx = document.getElementById("clients-chart");
|
const clientsCtx = document.getElementById("clients-chart");
|
||||||
const commandsCtx = document.getElementById("commands-chart");
|
const commandsCtx = document.getElementById("commands-chart");
|
||||||
@@ -403,10 +434,10 @@ function initCharts() {
|
|||||||
sessionsChart = sessionsCtx ? new Chart(sessionsCtx, {
|
sessionsChart = sessionsCtx ? new Chart(sessionsCtx, {
|
||||||
type: "doughnut",
|
type: "doughnut",
|
||||||
data: {
|
data: {
|
||||||
labels: ["Console", "Remote Desktop", "Files", "Processes"],
|
labels: ["No active sessions"],
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: [0, 0, 0, 0],
|
data: [1],
|
||||||
backgroundColor: ["#34d399", "#c084fc", "#60a5fa", "#fb923c"],
|
backgroundColor: [SESSION_EMPTY_COLOR],
|
||||||
borderColor: "#0f172a",
|
borderColor: "#0f172a",
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
}],
|
}],
|
||||||
@@ -417,8 +448,17 @@ function initCharts() {
|
|||||||
animation: false,
|
animation: false,
|
||||||
cutout: "64%",
|
cutout: "64%",
|
||||||
plugins: {
|
plugins: {
|
||||||
legend: { position: "right", labels: { boxWidth: 10, boxHeight: 10 } },
|
legend: { display: false, position: "right", labels: { boxWidth: 10, boxHeight: 10 } },
|
||||||
tooltip: chartTooltip(),
|
tooltip: {
|
||||||
|
...chartTooltip(),
|
||||||
|
callbacks: {
|
||||||
|
label: (ctx) => {
|
||||||
|
if (ctx.chart.data.labels?.[ctx.dataIndex] === "No active sessions") return "No active sessions";
|
||||||
|
const value = Number(ctx.parsed) || 0;
|
||||||
|
return `${ctx.label}: ${value.toLocaleString()} session${value === 1 ? "" : "s"}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}) : null;
|
}) : null;
|
||||||
@@ -533,11 +573,7 @@ function updateMetrics(data, debug) {
|
|||||||
);
|
);
|
||||||
animateCounter(document.getElementById("clients-total"), data.clients.total);
|
animateCounter(document.getElementById("clients-total"), data.clients.total);
|
||||||
|
|
||||||
const totalSessions =
|
const totalSessions = getSessionValues(data.sessions).reduce((sum, value) => sum + value, 0);
|
||||||
data.sessions.console +
|
|
||||||
data.sessions.remoteDesktop +
|
|
||||||
data.sessions.fileBrowser +
|
|
||||||
data.sessions.process;
|
|
||||||
animateCounter(document.getElementById("active-sessions"), totalSessions);
|
animateCounter(document.getElementById("active-sessions"), totalSessions);
|
||||||
|
|
||||||
animateCounter(
|
animateCounter(
|
||||||
@@ -657,15 +693,7 @@ function updateMetrics(data, debug) {
|
|||||||
osList.innerHTML = '<div class="text-slate-500">No clients</div>';
|
osList.innerHTML = '<div class="text-slate-500">No clients</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sessionsChart) {
|
updateSessionsChart(data.sessions);
|
||||||
sessionsChart.data.datasets[0].data = [
|
|
||||||
data.sessions.console || 0,
|
|
||||||
data.sessions.remoteDesktop || 0,
|
|
||||||
data.sessions.fileBrowser || 0,
|
|
||||||
data.sessions.process || 0,
|
|
||||||
];
|
|
||||||
sessionsChart.update("none");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (osChart) {
|
if (osChart) {
|
||||||
const osEntries = Object.entries(data.clients.byOS || {})
|
const osEntries = Object.entries(data.clients.byOS || {})
|
||||||
|
|||||||
Reference in New Issue
Block a user