v0.36.3
This commit is contained in:
1 parent
5cb63f542c
commit
17e314e159
27 files changed
+1017
-291
No files matched your search
@@ -115,7 +115,7 @@ window.rustProxyChartScale = (() => {
|
||||
{ top = 0.08, bottom = 0.92, clipped = false, seriesScales = null } = {}) {
|
||||
const node = typeof target === "string" ? document.getElementById(target) : target;
|
||||
const svg = node?.tagName?.toLowerCase() === "svg" ? node : node?.ownerSVGElement;
|
||||
if (!svg) return;
|
||||
if (!svg || svg.classList.contains("ui-icon")) return;
|
||||
svg.rustProxyAxisData = {
|
||||
peak: Number.isFinite(peakValue) && peakValue > 0 ? peakValue : 1,
|
||||
unit, count: Number.isInteger(count) && count > 0 ? count : 0,
|
||||
@@ -127,7 +127,7 @@ window.rustProxyChartScale = (() => {
|
||||
}
|
||||
function refreshAxes() {
|
||||
const show = document.documentElement.dataset.chartAxes === "true";
|
||||
for (const svg of document.querySelectorAll("svg")) {
|
||||
for (const svg of document.querySelectorAll("svg:not(.ui-icon)")) {
|
||||
if (show && svg.rustProxyAxisData) renderAxes(svg);
|
||||
else if (!show && svg.parentElement?.classList.contains("rp-chart-axis-host")) {
|
||||
const host = svg.parentElement;
|
||||
|
||||
@@ -168,7 +168,7 @@ function uiIconForTarget(target) {
|
||||
if (manual && UI_ICON_SHAPES[manual]) return manual;
|
||||
if (target.matches(".chart-style-choice")) return null;
|
||||
if (target.matches(".overview-inline-grip, .overview-inline-narrow, .overview-inline-widen, .overview-inline-up, .overview-inline-down, .overview-inline-hide, .overview-layout-narrow, .overview-layout-widen, .overview-layout-up, .overview-layout-down, .overview-layout-hide")) return null;
|
||||
if (target.matches("#tunnels-open, .vhost-backend-protocol-badge, .config-history-day, .draft-dock-toggle")) return null;
|
||||
if (target.matches("#tunnels-open, .vhost-backend-protocol-badge, .config-history-day, .draft-dock-toggle, .mobile-menu-toggle")) return null;
|
||||
if (UI_GLYPH_LABEL.test(String(target.textContent || "").trim())) return null;
|
||||
if (UI_ID_ICONS[target.id]) return UI_ID_ICONS[target.id];
|
||||
if (target.matches("#web-service-preset-apply, [data-cache-memory-preset], [data-cache-cold-preset], [data-transform-preset]")) return "wand";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const ADMIN_THEMES = new Set(["dark", "ultra_dark", "light", "cream"]);
|
||||
const ADMIN_TIME_FORMATS = new Set(["24h", "12h"]);
|
||||
const ADMIN_CHART_STYLES = new Set(["default", "soft", "technical", "high_contrast", "neon", "monochrome", "warm", "cool"]);
|
||||
const ADMIN_CHART_STYLES = new Set(["default", "soft", "technical", "high_contrast", "neon", "monochrome", "warm", "cool", "sunset", "aurora", "ocean", "forest", "pastel", "terminal", "blueprint", "colorblind"]);
|
||||
const ADMIN_DENSITIES = new Set(["normal", "compact", "ultra"]);
|
||||
const ADMIN_BUTTON_STYLES = new Set(["normal", "compact"]);
|
||||
const ADMIN_CORNER_STYLES = new Set(["default", "square", "subtle", "rounded", "extra"]);
|
||||
@@ -16,7 +16,7 @@ const ADMIN_APPEARANCE_DEFAULTS = Object.freeze({
|
||||
chart_axes: false, interface_icons: false, logo_animation: false,
|
||||
button_style: "normal", corner_style: "default", table_density: "normal", dashboard_density: ADMIN_DASHBOARD_DEFAULTS.dashboard_density, dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS], dashboard_hidden_widgets: [...ADMIN_DEFAULT_HIDDEN_WIDGETS], dashboard_widget_sizes: null,
|
||||
});
|
||||
const CHART_STYLE_KEYS = Object.freeze({ default: "chartStyleDefault", soft: "chartStyleSoft", technical: "chartStyleTechnical", high_contrast: "chartStyleHighContrast", neon: "chartStyleNeon", monochrome: "chartStyleMonochrome", warm: "chartStyleWarm", cool: "chartStyleCool" });
|
||||
const CHART_STYLE_KEYS = Object.freeze({ default: "chartStyleDefault", soft: "chartStyleSoft", technical: "chartStyleTechnical", high_contrast: "chartStyleHighContrast", neon: "chartStyleNeon", monochrome: "chartStyleMonochrome", warm: "chartStyleWarm", cool: "chartStyleCool", sunset: "chartStyleSunset", aurora: "chartStyleAurora", ocean: "chartStyleOcean", forest: "chartStyleForest", pastel: "chartStylePastel", terminal: "chartStyleTerminal", blueprint: "chartStyleBlueprint", colorblind: "chartStyleColorblind" });
|
||||
let adminPreferences = null, adminPreferencesLoading = null, adminPreferencesWrite = Promise.resolve(), adminPreferencesUnavailable = false;
|
||||
|
||||
function normalizeAdminTheme(value) { return ADMIN_THEMES.has(value) ? value : "dark"; }
|
||||
|
||||
@@ -282,6 +282,15 @@ function svgNode(tag, attrs = {}) {
|
||||
|
||||
function setChartText(node, value) {
|
||||
const text = String(value);
|
||||
// Controls decorated by the optional SVG icons hold [svg.ui-icon, text]; keep the icon
|
||||
// and update only the text node so periodic refreshes do not rebuild the button.
|
||||
const icon = node.querySelector(":scope > svg.ui-icon");
|
||||
if (icon) {
|
||||
const last = node.lastChild;
|
||||
if (last?.nodeType === 3) { if (last.data !== text) last.data = text; }
|
||||
else node.append(text);
|
||||
return;
|
||||
}
|
||||
if (node.firstChild?.nodeType === 3 && node.firstChild === node.lastChild) {
|
||||
if (node.firstChild.data !== text) node.firstChild.data = text;
|
||||
} else if (node.textContent !== text) {
|
||||
@@ -346,9 +355,12 @@ function renderNetworkInterfaceCharts(interfaces, appendSample) {
|
||||
setChartText(row.querySelector(".network-interface-hide"), t("hideMetric"));
|
||||
row.querySelector(".network-rx-line").setAttribute("points", sparklinePoints(history.rx, 300, 60, 5, peak) || "0,55 300,55");
|
||||
row.querySelector(".network-tx-line").setAttribute("points", sparklinePoints(history.tx, 300, 60, 5, peak) || "0,55 300,55");
|
||||
window.rustProxyChartScale.axes(row.querySelector("svg"), peak, "bytes/s", history.rx.length,
|
||||
// The Hide button precedes the chart and may carry an injected svg.ui-icon:
|
||||
// address the chart explicitly so axes/labels never attach to the icon.
|
||||
const chart = row.querySelector("svg:not(.ui-icon)");
|
||||
window.rustProxyChartScale.axes(chart, peak, "bytes/s", history.rx.length,
|
||||
{ top: 5 / 60, bottom: 55 / 60 });
|
||||
row.querySelector("svg").setAttribute("aria-label", `${name} ${t("networkInterfacesHistory")}`);
|
||||
chart.setAttribute("aria-label", `${name} ${t("networkInterfacesHistory")}`);
|
||||
children.push(row);
|
||||
}
|
||||
const hidden = current.filter(item => item?.name && hiddenNetworkInterfaces.has(item.name));
|
||||
@@ -395,15 +407,32 @@ function cacheOutcomeMix(totals) {
|
||||
const counts = [hits, misses, bypasses, requests - cacheTotal];
|
||||
return { counts, percentages: counts.map(value => value / requests * 100), requests };
|
||||
}
|
||||
// Percent labels live inside the bar segments; a label that does not fit is hidden
|
||||
// (the legend below always carries the exact value).
|
||||
function fitCacheMixLabels() {
|
||||
const bar = $("cache-mix-bar");
|
||||
if (!bar) return;
|
||||
bar.querySelectorAll(":scope > span").forEach(segment => {
|
||||
segment.classList.remove("is-tight");
|
||||
segment.classList.toggle("is-tight", segment.textContent !== "" && segment.scrollWidth > segment.clientWidth);
|
||||
});
|
||||
if (!bar.dataset.fitObserved && typeof ResizeObserver === "function") {
|
||||
bar.dataset.fitObserved = "1";
|
||||
new ResizeObserver(() => fitCacheMixLabels()).observe(bar);
|
||||
}
|
||||
}
|
||||
function renderCacheMix(mix, totalRequests) {
|
||||
const names = ["hit", "miss", "bypass", "other"];
|
||||
const unavailable = t(totalRequests === 0 ? "cacheMixWaiting" : "cacheMixInvalid");
|
||||
names.forEach((name, i) => {
|
||||
const pct = mix ? mix.percentages[i] : 0;
|
||||
$(`cache-mix-${name}`).style.width = `${pct}%`;
|
||||
const segment = $(`cache-mix-${name}`);
|
||||
segment.style.width = `${pct}%`;
|
||||
segment.textContent = mix && pct > 0 ? `${fmt(pct, pct < 10 ? 1 : 0)}%` : "";
|
||||
$(`cache-mix-${name}-count`).textContent = mix ? fmt(mix.counts[i]) : "-";
|
||||
$(`cache-mix-${name}-percent`).textContent = mix ? `${fmt(pct, 1)}%` : "-";
|
||||
});
|
||||
fitCacheMixLabels();
|
||||
$("cache-mix-headline").textContent = mix ? `${fmt(mix.percentages[0], 1)}% HIT` : "-";
|
||||
const caption = $("cache-mix-caption");
|
||||
const validTotal = Number.isSafeInteger(totalRequests) && totalRequests >= 0;
|
||||
@@ -424,6 +453,7 @@ function renderCacheMix(mix, totalRequests) {
|
||||
function renderDiagnostics(status, appendSample = true, systemSample = appendSample) {
|
||||
const d = status.system || {}, live = status.live_system || d, c = status.cache || {}, m = status.metrics || {};
|
||||
$("metric-h3").textContent = fmt(m.http3_requests);
|
||||
$("metric-h3-active").textContent = fmt(m.http3_active_connections || 0);
|
||||
const cacheHits = c.hits == null ? null : Number(c.hits), cacheMisses = c.misses == null ? null : Number(c.misses);
|
||||
const cacheEvents = cacheHits !== null && cacheMisses !== null ? cacheHits + cacheMisses : 0;
|
||||
$("metric-cache-ratio").textContent = cacheEvents > 0 ? `${fmt(cacheHits / cacheEvents * 100, 1)}%` : "-";
|
||||
|
||||
Reference in new issue
Block a user