v0.36.3
This commit is contained in:
1 parent
5cb63f542c
commit
17e314e159
27 files changed
+1017
-291
No files matched your search
+10
-2
@@ -2,7 +2,7 @@
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "RustProxy Administration API",
|
||||
"version": "0.36.2",
|
||||
"version": "0.36.3",
|
||||
"description": "Administration API for the active panel origin. Sign in through the panel; the same-origin HttpOnly cookie authenticates all private operations. Mutations also require the exact Origin, X-RustProxy-Request: 1 and a session-bound X-CSRF-Token. Loopback HTTP is the default; Settings can enable HTTPS before using a non-loopback administration bind. This document contains no live configuration or credentials. Object schemas marked extensible are summaries: full configuration validation is authoritative in Rust. The API also permits explicitly scoped GeneralApiBearer tokens on a narrow route allowlist, with RO/RW and source CIDR checks; API-token management and Prometheus-token management are browser-session-only."
|
||||
},
|
||||
"servers": [
|
||||
@@ -3812,7 +3812,15 @@
|
||||
"neon",
|
||||
"monochrome",
|
||||
"warm",
|
||||
"cool"
|
||||
"cool",
|
||||
"sunset",
|
||||
"aurora",
|
||||
"ocean",
|
||||
"forest",
|
||||
"pastel",
|
||||
"terminal",
|
||||
"blueprint",
|
||||
"colorblind"
|
||||
],
|
||||
"default": "default",
|
||||
"description": "Account-scoped visual presentation preset applied consistently to administration charts."
|
||||
|
||||
@@ -303,6 +303,14 @@ fn validate_admin_preferences(preferences: &AdminPreferences) -> Result<(), ApiE
|
||||
| "monochrome"
|
||||
| "warm"
|
||||
| "cool"
|
||||
| "sunset"
|
||||
| "aurora"
|
||||
| "ocean"
|
||||
| "forest"
|
||||
| "pastel"
|
||||
| "terminal"
|
||||
| "blueprint"
|
||||
| "colorblind"
|
||||
) {
|
||||
return Err(ApiError(
|
||||
StatusCode::UNPROCESSABLE_ENTITY,
|
||||
|
||||
@@ -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)}%` : "-";
|
||||
|
||||
@@ -162,7 +162,12 @@
|
||||
$("cp-expired").textContent = `${number(m.evictions)} / ${number(m.expired)}`;
|
||||
$("cp-rejected").textContent = `${t("cacheRejected")}: ${number(m.rejected_fills)} · ${t("cacheMemoryPressureShort")}: ${number(m.memory_pressure_rejections)} · ${t("cacheNukeLimitShort")}: ${number(m.hot_eviction_limited)}`;
|
||||
$("cache-domain-rows").replaceChildren(...shownGroups.map(row => {
|
||||
const tr = el("tr"); for (const value of [row.vhost || t("cacheLegacy"), row.domain, number(row.hot_entries), number(row.cold_entries), fmtBytes(row.resident_bytes), fmtBytes(row.cold_bytes), `${number(row.hits)} / ${number(row.misses)} / ${number(row.bypasses)}`, `${fmt((row.hit_ratio || 0) * 100, 1)}%`]) tr.append(el("td", value));
|
||||
const tr = el("tr"); for (const value of [row.vhost || t("cacheLegacy"), row.domain, number(row.hot_entries), number(row.cold_entries), fmtBytes(row.resident_bytes), fmtBytes(row.cold_bytes)]) tr.append(el("td", value));
|
||||
// HIT / MISS / BYPASS: coloured counts that match the dashboard cache bar, plus a hit-ratio meter.
|
||||
const outcomes = el("td", undefined, "cache-outcomes-cell");
|
||||
[[row.hits, "cache-outcome-hit"], [row.misses, "cache-outcome-miss"], [row.bypasses, "cache-outcome-bypass"]].forEach(([count, cls], index) => { if (index) outcomes.append(el("span", "/", "cache-outcome-sep")); outcomes.append(el("span", number(count), cls)); });
|
||||
const ratioPercent = Math.max(0, Math.min(100, (row.hit_ratio || 0) * 100)), ratio = el("td", undefined, "cache-ratio-cell"), meter = el("span", undefined, "cache-ratio-meter"), fill = el("i"); fill.style.width = `${ratioPercent}%`; meter.append(fill); ratio.append(el("span", `${fmt(ratioPercent, 1)}%`, "cache-ratio-value"), meter);
|
||||
tr.append(outcomes, ratio);
|
||||
const td = el("td", undefined, "cache-reasons"); for (const [key, count] of Object.entries(row.reasons || {}).sort((a, b) => b[1] - a[1])) { const tag = el("span", `${reason(key)}: ${number(count)}`, "cache-reason"); tag.title = key; td.append(tag); } tr.append(td); return tr;
|
||||
}));
|
||||
const domainEmpty = $("cache-domains-empty");
|
||||
|
||||
+208
-14
@@ -257,20 +257,6 @@ html[data-theme=cream] {
|
||||
--scrollbar-thumb-hover: #978a76;
|
||||
}
|
||||
|
||||
body[data-density=dense] {
|
||||
--ui-gap: 4px;
|
||||
--ui-card: 7px;
|
||||
--ui-font: 11.5px;
|
||||
--ui-control: 25px;
|
||||
}
|
||||
|
||||
body[data-density=comfortable] {
|
||||
--ui-gap: 13px;
|
||||
--ui-card: 17px;
|
||||
--ui-font: 14px;
|
||||
--ui-control: 36px;
|
||||
}
|
||||
|
||||
html[data-button-style=compact] body {
|
||||
--button-padding: 3px 7px;
|
||||
--button-font-size: 10px;
|
||||
@@ -333,6 +319,62 @@ html[data-button-style=compact] body {
|
||||
--sw4: #70d7ff;
|
||||
}
|
||||
|
||||
.chart-style-choice[data-chart-preset=sunset] {
|
||||
--sw1: #ff7a59;
|
||||
--sw2: #ffb347;
|
||||
--sw3: #e8509b;
|
||||
--sw4: #9b6bff;
|
||||
}
|
||||
|
||||
.chart-style-choice[data-chart-preset=aurora] {
|
||||
--sw1: #4ff0b0;
|
||||
--sw2: #6ec8ff;
|
||||
--sw3: #b78cff;
|
||||
--sw4: #ff7ad9;
|
||||
}
|
||||
|
||||
.chart-style-choice[data-chart-preset=ocean] {
|
||||
--sw1: #3fa7ff;
|
||||
--sw2: #2fd0c0;
|
||||
--sw3: #6f8cff;
|
||||
--sw4: #9be7ff;
|
||||
}
|
||||
|
||||
.chart-style-choice[data-chart-preset=forest] {
|
||||
--sw1: #7bc96f;
|
||||
--sw2: #d6c45a;
|
||||
--sw3: #4fae9a;
|
||||
--sw4: #c98f5c;
|
||||
}
|
||||
|
||||
.chart-style-choice[data-chart-preset=pastel] {
|
||||
--sw1: #f4b6c2;
|
||||
--sw2: #b5e0c2;
|
||||
--sw3: #b4c8f5;
|
||||
--sw4: #e3c8f0;
|
||||
}
|
||||
|
||||
.chart-style-choice[data-chart-preset=terminal] {
|
||||
--sw1: #6bff7a;
|
||||
--sw2: #e5ff6b;
|
||||
--sw3: #4fd0a0;
|
||||
--sw4: #ffb347;
|
||||
}
|
||||
|
||||
.chart-style-choice[data-chart-preset=blueprint] {
|
||||
--sw1: #cfe6ff;
|
||||
--sw2: #8fc4ff;
|
||||
--sw3: #ffffff;
|
||||
--sw4: #7aa8e0;
|
||||
}
|
||||
|
||||
.chart-style-choice[data-chart-preset=colorblind] {
|
||||
--sw1: #e69f00;
|
||||
--sw2: #56b4e9;
|
||||
--sw3: #009e73;
|
||||
--sw4: #cc79a7;
|
||||
}
|
||||
|
||||
html[data-chart-style=default] {
|
||||
--chart-accent: var(--accent);
|
||||
--chart-secondary: var(--green);
|
||||
@@ -485,6 +527,158 @@ html[data-chart-style=warm] {
|
||||
--chart-svg-filter: saturate(1.1) brightness(1.04);
|
||||
}
|
||||
|
||||
html[data-chart-style=sunset] {
|
||||
--chart-linecap: round;
|
||||
--chart-linejoin: round;
|
||||
--chart-accent: #ff7a59;
|
||||
--chart-secondary: #ffb347;
|
||||
--chart-tertiary: #e8509b;
|
||||
--chart-quaternary: #9b6bff;
|
||||
--chart-quinary: #ffd479;
|
||||
--chart-senary: #ff9fb2;
|
||||
--chart-septenary: #c08ad8;
|
||||
--chart-octonary: #8f6aa8;
|
||||
--chart-surface: color-mix(in srgb, var(--panel2) 90%, #3a1428 10%);
|
||||
--chart-surface-alt: color-mix(in srgb, var(--panel) 92%, #2e1022 8%);
|
||||
--chart-line-width: 2.5;
|
||||
--chart-grid-opacity: .36;
|
||||
--chart-grid-dash: 1 0;
|
||||
--chart-svg-filter: saturate(1.12) brightness(1.04);
|
||||
}
|
||||
|
||||
html[data-chart-style=aurora] {
|
||||
--chart-linecap: round;
|
||||
--chart-linejoin: round;
|
||||
--chart-accent: #4ff0b0;
|
||||
--chart-secondary: #6ec8ff;
|
||||
--chart-tertiary: #b78cff;
|
||||
--chart-quaternary: #ff7ad9;
|
||||
--chart-quinary: #c8ff7a;
|
||||
--chart-senary: #7affea;
|
||||
--chart-septenary: #8fa0ff;
|
||||
--chart-octonary: #d0a8ff;
|
||||
--chart-surface: color-mix(in srgb, var(--panel2) 91%, #0a2630 9%);
|
||||
--chart-surface-alt: color-mix(in srgb, var(--panel) 92%, #082028 8%);
|
||||
--chart-line-width: 2.4;
|
||||
--chart-grid-opacity: .4;
|
||||
--chart-grid-dash: 2 5;
|
||||
--chart-svg-filter: saturate(1.2) brightness(1.08);
|
||||
}
|
||||
|
||||
html[data-chart-style=ocean] {
|
||||
--chart-linecap: round;
|
||||
--chart-linejoin: round;
|
||||
--chart-accent: #3fa7ff;
|
||||
--chart-secondary: #2fd0c0;
|
||||
--chart-tertiary: #6f8cff;
|
||||
--chart-quaternary: #9be7ff;
|
||||
--chart-quinary: #52e0a8;
|
||||
--chart-senary: #78b8ff;
|
||||
--chart-septenary: #4a7fb5;
|
||||
--chart-octonary: #5f9ea8;
|
||||
--chart-surface: color-mix(in srgb, var(--panel2) 90%, #061c33 10%);
|
||||
--chart-surface-alt: color-mix(in srgb, var(--panel) 92%, #05182b 8%);
|
||||
--chart-line-width: 2.2;
|
||||
--chart-grid-opacity: .4;
|
||||
--chart-grid-dash: 2 5;
|
||||
--chart-svg-filter: saturate(1.05);
|
||||
}
|
||||
|
||||
html[data-chart-style=forest] {
|
||||
--chart-linecap: round;
|
||||
--chart-linejoin: round;
|
||||
--chart-accent: #7bc96f;
|
||||
--chart-secondary: #d6c45a;
|
||||
--chart-tertiary: #4fae9a;
|
||||
--chart-quaternary: #c98f5c;
|
||||
--chart-quinary: #a4d86a;
|
||||
--chart-senary: #e0a84f;
|
||||
--chart-septenary: #7aa86a;
|
||||
--chart-octonary: #8c7a5a;
|
||||
--chart-surface: color-mix(in srgb, var(--panel2) 91%, #11230f 9%);
|
||||
--chart-surface-alt: color-mix(in srgb, var(--panel) 92%, #0e1d0d 8%);
|
||||
--chart-line-width: 2.3;
|
||||
--chart-grid-opacity: .34;
|
||||
--chart-grid-dash: 1 0;
|
||||
--chart-svg-filter: saturate(.96);
|
||||
}
|
||||
|
||||
html[data-chart-style=pastel] {
|
||||
--chart-linecap: round;
|
||||
--chart-linejoin: round;
|
||||
--chart-accent: #f4b6c2;
|
||||
--chart-secondary: #b5e0c2;
|
||||
--chart-tertiary: #b4c8f5;
|
||||
--chart-quaternary: #e3c8f0;
|
||||
--chart-quinary: #f6dba4;
|
||||
--chart-senary: #a8dcdc;
|
||||
--chart-septenary: #d2b8e8;
|
||||
--chart-octonary: #b9c2cc;
|
||||
--chart-surface: color-mix(in srgb, var(--panel2) 90%, #fff 10%);
|
||||
--chart-surface-alt: color-mix(in srgb, var(--panel) 93%, #fff 7%);
|
||||
--chart-line-width: 3;
|
||||
--chart-grid-opacity: .44;
|
||||
--chart-grid-dash: 1 0;
|
||||
--chart-svg-filter: saturate(.82) brightness(1.08);
|
||||
}
|
||||
|
||||
html[data-chart-style=terminal] {
|
||||
--chart-linecap: square;
|
||||
--chart-linejoin: miter;
|
||||
--chart-accent: #6bff7a;
|
||||
--chart-secondary: #e5ff6b;
|
||||
--chart-tertiary: #4fd0a0;
|
||||
--chart-quaternary: #ffb347;
|
||||
--chart-quinary: #a6ff9a;
|
||||
--chart-senary: #d4ff9a;
|
||||
--chart-septenary: #58b868;
|
||||
--chart-octonary: #7a8f58;
|
||||
--chart-surface: color-mix(in srgb, var(--panel2) 88%, #031a07 12%);
|
||||
--chart-surface-alt: color-mix(in srgb, var(--panel) 90%, #021405 10%);
|
||||
--chart-line-width: 1.6;
|
||||
--chart-grid-opacity: .7;
|
||||
--chart-grid-dash: 1 3;
|
||||
--chart-svg-filter: saturate(1.1) contrast(1.1);
|
||||
}
|
||||
|
||||
html[data-chart-style=blueprint] {
|
||||
--chart-linecap: square;
|
||||
--chart-linejoin: miter;
|
||||
--chart-accent: #cfe6ff;
|
||||
--chart-secondary: #8fc4ff;
|
||||
--chart-tertiary: #ffffff;
|
||||
--chart-quaternary: #7aa8e0;
|
||||
--chart-quinary: #a8d0ff;
|
||||
--chart-senary: #e8f2ff;
|
||||
--chart-septenary: #6a90c0;
|
||||
--chart-octonary: #506c94;
|
||||
--chart-surface: color-mix(in srgb, var(--panel2) 84%, #0a2a5c 16%);
|
||||
--chart-surface-alt: color-mix(in srgb, var(--panel) 88%, #08224a 12%);
|
||||
--chart-line-width: 1.3;
|
||||
--chart-grid-opacity: .78;
|
||||
--chart-grid-dash: 4 4;
|
||||
--chart-svg-filter: saturate(.9) contrast(1.06);
|
||||
}
|
||||
|
||||
html[data-chart-style=colorblind] {
|
||||
--chart-linecap: round;
|
||||
--chart-linejoin: round;
|
||||
--chart-accent: #e69f00;
|
||||
--chart-secondary: #56b4e9;
|
||||
--chart-tertiary: #009e73;
|
||||
--chart-quaternary: #cc79a7;
|
||||
--chart-quinary: #f0e442;
|
||||
--chart-senary: #0072b2;
|
||||
--chart-septenary: #d55e00;
|
||||
--chart-octonary: #bdbdbd;
|
||||
--chart-surface: color-mix(in srgb, var(--panel2) 94%, #000 6%);
|
||||
--chart-surface-alt: color-mix(in srgb, var(--panel) 94%, #000 6%);
|
||||
--chart-line-width: 2.6;
|
||||
--chart-grid-opacity: .7;
|
||||
--chart-grid-dash: 3 4;
|
||||
--chart-svg-filter: contrast(1.1);
|
||||
}
|
||||
|
||||
html[data-chart-style] {
|
||||
--traffic-h1: var(--chart-accent);
|
||||
--traffic-h2: var(--chart-secondary);
|
||||
|
||||
@@ -1067,43 +1067,10 @@ dialog .vh-form,
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
body[data-density=compact] {
|
||||
--ui-gap: 2px;
|
||||
--ui-card: 5px;
|
||||
--ui-font: 10.75px;
|
||||
--ui-control: 22px;
|
||||
line-height: 1.32;
|
||||
}
|
||||
|
||||
body[data-density=compact] main {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .card-heading {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .card-heading h2,
|
||||
html[data-dashboard-density=compact] #panel-overview .dashboard-overview-grid>.card .card-heading h2 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .outline,
|
||||
body[data-density=compact] .primary,
|
||||
body[data-density=compact] .quiet,
|
||||
body[data-density=compact] button,
|
||||
body[data-density=compact] input:not([type=checkbox]):not([type=radio]),
|
||||
body[data-density=compact] select,
|
||||
body[data-density=compact] textarea {
|
||||
padding: 3px 7px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .page-footer {
|
||||
padding: 7px 0;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.network-interface-row-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -1151,7 +1118,7 @@ body[data-density=compact] .page-footer {
|
||||
font: 10px var(--mono);
|
||||
}
|
||||
|
||||
.network-interface-row svg {
|
||||
.network-interface-row svg:not(.ui-icon) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
@@ -1251,6 +1218,29 @@ body[data-density=compact] .page-footer {
|
||||
min-height: 24px;
|
||||
padding: 3px 7px;
|
||||
font: 9px var(--mono);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Small controls: a smaller icon must not change the button height when the
|
||||
optional SVG icons are toggled or re-applied during a refresh (Safari jumped). */
|
||||
.network-interface-hide>.ui-icon,
|
||||
.network-interface-hidden .quiet>.ui-icon {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
margin-inline-end: 4px;
|
||||
vertical-align: 0;
|
||||
}
|
||||
|
||||
html[data-interface-icons="true"] .network-interface-hide>svg.ui-icon,
|
||||
html[data-interface-icons="true"] .network-interface-hidden .quiet>svg.ui-icon {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
}
|
||||
|
||||
.network-interface-charts {
|
||||
overflow-anchor: none;
|
||||
}
|
||||
|
||||
.network-interface-row+.network-interface-row,
|
||||
@@ -1570,14 +1560,6 @@ html[data-table-density=ultra] :is(table th, table td) {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.path-permissions-commands {
|
||||
max-height: 180px;
|
||||
}
|
||||
|
||||
.path-permissions-actions {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.path-permissions-options>summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1599,6 +1581,7 @@ html[data-table-density=ultra] :is(table th, table td) {
|
||||
}
|
||||
|
||||
.path-permissions-commands {
|
||||
max-height: 180px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -1608,4 +1591,13 @@ html[data-table-density=ultra] :is(table th, table td) {
|
||||
|
||||
.path-permissions-actions {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
/* Safety net: whatever chart/card rule is added later, injected UI icons stay inline,
|
||||
fixed-size and out of layout flow (they used to stretch inside chart cards on mobile Safari). */
|
||||
html[data-interface-icons="true"] :is(button, a, summary)>svg.ui-icon {
|
||||
display: inline-block;
|
||||
position: static;
|
||||
flex: 0 0 auto;
|
||||
max-width: none;
|
||||
overflow: visible;
|
||||
}
|
||||
@@ -604,37 +604,6 @@ main {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .shell {
|
||||
grid-template-columns: 164px minmax(0, 1fr);
|
||||
}
|
||||
|
||||
body[data-density=compact] .sidebar {
|
||||
padding: 14px 9px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .nav,
|
||||
body[data-density=compact] .stat {
|
||||
padding: 6px 7px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .topbar {
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .page-intro {
|
||||
padding: 7px 0 6px;
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .page-intro h1 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .page-intro .lead {
|
||||
font-size: 10px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.top-log-menu>summary,
|
||||
.backend-column-picker>summary,
|
||||
.file-log-search-help>summary {
|
||||
|
||||
@@ -280,7 +280,7 @@ html[data-theme=cream] :is(.card, .stat, dialog) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mini-live-chart svg {
|
||||
.mini-live-chart svg:not(.ui-icon) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
@@ -361,11 +361,11 @@ html[data-theme=cream] :is(.card, .stat, dialog) {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.activity-card svg {
|
||||
.activity-card svg:not(.ui-icon) {
|
||||
height: 105px;
|
||||
}
|
||||
|
||||
.system-card svg {
|
||||
.system-card svg:not(.ui-icon) {
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
@@ -383,11 +383,6 @@ html[data-theme=cream] :is(.card, .stat, dialog) {
|
||||
max-height: 205px;
|
||||
}
|
||||
|
||||
body[data-density=dense] .stat strong {
|
||||
font-size: 22px;
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
.traffic-chart-grid,
|
||||
.logging-grid {
|
||||
display: grid;
|
||||
@@ -468,7 +463,7 @@ body[data-density=dense] .stat strong {
|
||||
padding: 7px 10px 0;
|
||||
}
|
||||
|
||||
.vhost-chart svg {
|
||||
.vhost-chart svg:not(.ui-icon) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 54px;
|
||||
@@ -550,37 +545,12 @@ body[data-density=dense] .stat strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body[data-density=compact] .stat strong {
|
||||
font-size: 18px;
|
||||
margin: 1px 0;
|
||||
}
|
||||
|
||||
body[data-density=compact] .stat p,
|
||||
body[data-density=compact] .stat small,
|
||||
html[data-dashboard-density=normal] #panel-overview .stat small,
|
||||
html[data-dashboard-density=ultra] #panel-overview .stat-cache-outcomes .cache-mix-header>span,
|
||||
html[data-dashboard-density=ultra] #panel-overview .stat-cache-outcomes .cache-mix-caption {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .activity-card svg {
|
||||
height: 84px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .system-card svg {
|
||||
height: 66px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .pool-table td,
|
||||
body[data-density=compact] .pool-table th {
|
||||
padding: 3px 5px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .pool-card .table-scroll {
|
||||
max-height: 170px;
|
||||
}
|
||||
|
||||
.network-interface-charts {
|
||||
display: grid;
|
||||
max-height: 260px;
|
||||
@@ -664,7 +634,7 @@ body[data-density=compact] .pool-card .table-scroll {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.stat-chart svg {
|
||||
.stat-chart svg:not(.ui-icon) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 26px;
|
||||
@@ -769,7 +739,7 @@ body[data-density=compact] .pool-card .table-scroll {
|
||||
padding: 14px 15px 12px;
|
||||
}
|
||||
|
||||
.function-live-chart svg {
|
||||
.function-live-chart svg:not(.ui-icon) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
@@ -851,7 +821,7 @@ body[data-density=compact] .pool-card .table-scroll {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.connection-card svg {
|
||||
.connection-card svg:not(.ui-icon) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
@@ -1052,7 +1022,7 @@ body[data-density=compact] .pool-card .table-scroll {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
:is(.stat-chart, .activity-card, .system-card, .function-live-chart) svg,
|
||||
:is(.stat-chart, .activity-card, .system-card, .function-live-chart) svg:not(.ui-icon),
|
||||
:is(.traffic-donut, .traffic-bar-chart span) {
|
||||
filter: var(--chart-svg-filter);
|
||||
}
|
||||
@@ -1127,15 +1097,15 @@ html[data-dashboard-density=ultra] #panel-overview .stat small {
|
||||
line-height: 1.12;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=ultra] #panel-overview .stat-chart svg {
|
||||
html[data-dashboard-density=ultra] #panel-overview .stat-chart svg:not(.ui-icon) {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=normal] #panel-overview .stat-chart svg {
|
||||
html[data-dashboard-density=normal] #panel-overview .stat-chart svg:not(.ui-icon) {
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=compact] #panel-overview .stat-chart svg {
|
||||
html[data-dashboard-density=compact] #panel-overview .stat-chart svg:not(.ui-icon) {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
@@ -1737,7 +1707,7 @@ html:is([data-corner-style=square], [data-corner-style=subtle], [data-corner-sty
|
||||
border-radius: var(--rp-radius-surface) !important;
|
||||
}
|
||||
|
||||
html:is([data-corner-style=square], [data-corner-style=subtle], [data-corner-style=rounded], [data-corner-style=extra]) :is(button:not(.nav):not(.file-log-tab):not(.vhost-backend-trigger), input:not([type=checkbox]):not([type=radio]):not([type=range]), select, textarea, .pill, .vhost-backend-protocol-badge, .overview-widget-type, .badge, .quiet, .outline, .primary, .code, .command, .dashboard-widget-toggle, .settings-tabs button, .overview-inline-restore),
|
||||
html:is([data-corner-style=square], [data-corner-style=subtle], [data-corner-style=rounded], [data-corner-style=extra]) :is(button:not(.nav):not(.file-log-tab):not(.vhost-backend-trigger), input:not([type=checkbox]):not([type=radio]):not([type=range]), select, textarea, .pill, .vhost-backend-protocol-badge, .overview-widget-type, .quiet, .outline, .primary, .code, .command, .dashboard-widget-toggle, .settings-tabs button, .overview-inline-restore),
|
||||
html:is([data-corner-style=square], [data-corner-style=subtle], [data-corner-style=rounded], [data-corner-style=extra]) :is(.nav, .file-log-tab, .vhost-backend-trigger, .backend-column-options, .docker-service-quick-actions a, .docker-service-quick-actions button, .docker-view-toggle, .provider-picker, .renewal-meta-item) {
|
||||
border-radius: var(--rp-radius-control) !important;
|
||||
}
|
||||
@@ -2074,7 +2044,7 @@ html:is([data-corner-style=square], [data-corner-style=subtle], [data-corner-sty
|
||||
gap: 8px;
|
||||
padding: 9px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--rp-radius-surface, var(--radius, 8px));
|
||||
border-radius: var(--rp-radius-surface, 8px);
|
||||
background: var(--panel);
|
||||
}
|
||||
|
||||
@@ -2213,8 +2183,8 @@ html[data-dashboard-density] #panel-overview .stat :is(.stat-chart-legend, .over
|
||||
#panel-overview .stat-cache-outcomes .cache-mix-bar {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 12px;
|
||||
margin: 7px 0 9px;
|
||||
height: 20px;
|
||||
margin: 3px 0 4px;
|
||||
border-radius: var(--rp-progress-radius);
|
||||
background: var(--rp-progress-track);
|
||||
overflow: hidden;
|
||||
@@ -2224,6 +2194,17 @@ html[data-dashboard-density] #panel-overview .stat :is(.stat-chart-legend, .over
|
||||
display: block;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
padding: 0 2px;
|
||||
overflow: hidden;
|
||||
color: #0c0e11;
|
||||
font: 600 10px/20px var(--mono, ui-monospace, monospace);
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#panel-overview .cache-mix-bar>span.is-tight {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
#panel-overview .cache-mix-other {
|
||||
@@ -2322,4 +2303,61 @@ html[data-dashboard-density] #panel-overview .stat :is(.stat-chart-legend, .over
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
/* WebSocket tunnels: "Established" sits to the right of the main value instead of a third text line. */
|
||||
#panel-overview .stat .stat-value-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
column-gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#panel-overview .stat .stat-value-row>strong {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
#panel-overview .stat .stat-value-row>.stat-side-value {
|
||||
display: block;
|
||||
margin: 0 0 0 auto;
|
||||
color: var(--muted);
|
||||
font-size: 10px;
|
||||
line-height: 1.3;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#panel-overview .stat .stat-value-row>.stat-side-value b {
|
||||
color: var(--text);
|
||||
font-family: var(--mono);
|
||||
font-size: 13px;
|
||||
font-weight: 450;
|
||||
}
|
||||
|
||||
/* Compact stat cards: a card made only of title, value and one secondary line shows that line
|
||||
beside the value (right-aligned) instead of on a line of its own. */
|
||||
#panel-overview .stats-grid>.stat:is(:not(.stat-donut, .stat-meter, .stat-with-action, .stat-chart):not(:has(>:not(span, strong, small))):has(>small)) {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
column-gap: 10px;
|
||||
align-items: baseline;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
#panel-overview .stats-grid>.stat:is(:not(.stat-donut, .stat-meter, .stat-with-action, .stat-chart):not(:has(>:not(span, strong, small))):has(>small))>span:first-child {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
#panel-overview .stats-grid>.stat:is(:not(.stat-donut, .stat-meter, .stat-with-action, .stat-chart):not(:has(>:not(span, strong, small))):has(>small))>strong {
|
||||
grid-column: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#panel-overview .stats-grid>.stat:is(:not(.stat-donut, .stat-meter, .stat-with-action, .stat-chart):not(:has(>:not(span, strong, small))):has(>small))>small {
|
||||
grid-column: 2;
|
||||
max-width: 14em;
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
@@ -29,7 +29,7 @@
|
||||
.traffic-chart-card,
|
||||
#panel-overview .backend-mode-bar span,
|
||||
#panel-overview .stats-grid>.stat,
|
||||
#panel-overview .dashboard-overview-grid>.activity-card svg,
|
||||
#panel-overview .dashboard-overview-grid>.activity-card svg:not(.ui-icon),
|
||||
#panel-overview .dashboard-overview-grid>[data-dashboard-widget],
|
||||
.dashboard-density-setting>.fine,
|
||||
.dashboard-density-setting>select,
|
||||
@@ -1140,7 +1140,7 @@ html[data-dashboard-density=ultra] #panel-overview .dashboard-overview-grid>.car
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 11px;
|
||||
background: var(--surface, transparent);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.vh-backend-health-editor h3 {
|
||||
@@ -1483,18 +1483,22 @@ html[data-dashboard-density=ultra] #panel-overview .dashboard-overview-grid>.car
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
/* Same geometry and typography as .pill so protocol indicators sit evenly in the
|
||||
Vhost policy row; only the colour (muted = not observed, green = observed) differs. */
|
||||
.vhost-backend-protocol-badge {
|
||||
display: inline-flex;
|
||||
gap: 4px;
|
||||
align-items: baseline;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
border: 1px solid var(--pill-line);
|
||||
border-radius: var(--rp-radius-control, 4px);
|
||||
background: var(--panel2);
|
||||
border-radius: var(--rp-radius-control, 0);
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
padding: 3px 7px;
|
||||
font: 10px var(--mono);
|
||||
min-height: 0;
|
||||
padding: 4px 8px;
|
||||
font: 9px/10px var(--mono);
|
||||
letter-spacing: 1px;
|
||||
overflow-wrap: anywhere;
|
||||
text-align: left;
|
||||
}
|
||||
@@ -1504,6 +1508,10 @@ html.app-loading,
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.vhost-policy-pills>.vhost-backend-protocol-badge {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.vhost-backend-protocol-badge[data-observed=true] {
|
||||
color: var(--green);
|
||||
border-color: var(--pill-live-line);
|
||||
@@ -1788,12 +1796,12 @@ html.app-loading,
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
gap: 7px;
|
||||
padding: 2px 4px 2px 9px;
|
||||
border-radius: var(--rp-radius-control, 15px);
|
||||
gap: 5px;
|
||||
padding: 4px 5px 4px 8px;
|
||||
border-radius: var(--rp-radius-control, 0);
|
||||
border: 1px solid var(--pill-live-line);
|
||||
background: var(--nav-selected-bg);
|
||||
font-size: 11px;
|
||||
background: var(--panel);
|
||||
font: 10px var(--mono);
|
||||
}
|
||||
|
||||
.acl-picker-tag>span {
|
||||
@@ -1803,13 +1811,12 @@ html.app-loading,
|
||||
|
||||
.acl-picker-tag .acl-picker-remove {
|
||||
border: none;
|
||||
border-radius: var(--rp-radius-control, 50%);
|
||||
border-radius: var(--rp-radius-control, 0);
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
font-size: 16px;
|
||||
padding: 0;
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
padding: 0 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -1940,4 +1947,76 @@ html.app-loading,
|
||||
.web-service-preset-toggles>.check {
|
||||
margin: 0 !important;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
/* Spacing review (0.36.2): descriptive text and blocks that used to touch the next
|
||||
element. Rules only add space where the layout had none; grid/flex gaps are untouched. */
|
||||
.fine+:is(.switch-grid, .settings-tabs, .table-scroll, .soft-card, .appearance-settings-grid, .runtime-information-grid, details),
|
||||
.form-actions+.fine,
|
||||
.table-scroll+:is(.empty, .fine),
|
||||
.empty+.file-logs-pager {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
:is(.card-heading, .window-heading)+.fine,
|
||||
h2+.fine {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.location-help-content :is(p, .fine)+:is(p, .fine) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.location-help-content :is(p, .fine, ul, ol, table, pre)+:is(h3, h4) {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.cache-toolbar+.function-live-chart,
|
||||
.function-live-chart+.stats-grid,
|
||||
.soft-card+.soft-card,
|
||||
.field-grid+.field-grid {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.function-live-chart-summary+.function-live-chart-body {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.tls-pqc-control>:is(.fine, a) {
|
||||
margin-block: 0;
|
||||
}
|
||||
|
||||
.tls-pqc-control {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.tls-pqc-control>a {
|
||||
justify-self: start;
|
||||
color: var(--accent);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#settings-page-tls-policy .switch-grid {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
#panel-settings .fine+.settings-tabs.sub-tabs,
|
||||
.fine+.field-grid,
|
||||
.vh-grid+.fine,
|
||||
.logs-card+.log-footnote,
|
||||
.overview-presets-content+.overview-layout-footer {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#settings-page-policies>.edit-form+div {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
@media (min-width: 761px) {
|
||||
#panel-settings .settings-tabs.sub-tabs+:is(div, form) {
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
@@ -130,7 +130,6 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
body[data-density=compact] .sidebar nav,
|
||||
.certificate-coverage {
|
||||
margin-top: 14px;
|
||||
}
|
||||
@@ -688,40 +687,6 @@ body[data-density=compact] .sidebar nav,
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .docker-service-row {
|
||||
padding: 6px 8px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .docker-service-head,
|
||||
body[data-density=compact] .security-stack {
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .docker-agent-overview {
|
||||
gap: 4px 12px;
|
||||
margin: 4px 0 6px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .docker-agent-details {
|
||||
margin-bottom: 6px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .docker-service-editor {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .docker-service-editor[open]>summary {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .security-editor {
|
||||
margin-top: 8px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.docker-agent-grid>label {
|
||||
display: grid;
|
||||
align-content: start;
|
||||
@@ -1294,4 +1259,224 @@ html[data-dashboard-density=normal] #panel-overview .stat>span,
|
||||
.global-rate-fields {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Settings rows (0.36.3): label and help on the left, control on the right, one setting per row. */
|
||||
#settings-page-appearance .appearance-section-heading .small-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-section-heading h3 {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(170px, 260px);
|
||||
grid-template-areas: "name control" "help control";
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
column-gap: 24px;
|
||||
row-gap: 3px;
|
||||
margin: 0;
|
||||
padding: 11px 0;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label:first-child {
|
||||
border-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label>span:first-child {
|
||||
grid-area: name;
|
||||
align-self: end;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label>:is(select, input[type=range]) {
|
||||
grid-area: control;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label>small {
|
||||
grid-area: help;
|
||||
align-self: start;
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label:not(:has(>small), .check) {
|
||||
grid-template-areas: "name control";
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label:not(:has(>small), .check)>span:first-child {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
#settings-page-appearance .refresh-settings-grid>label.check>span,
|
||||
#settings-page-appearance .dashboard-widget-settings-intro>span {
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-scale-control>span:first-child {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
/* Checkbox settings: text on the left, the checkbox on the right edge of the row
|
||||
(.check is display:flex !important, so the row is reversed instead of using grid areas). */
|
||||
#settings-page-appearance .appearance-settings-grid>label.check {
|
||||
flex-direction: row-reverse;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
align-self: auto;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label.check>input {
|
||||
flex: 0 0 auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label.check>span {
|
||||
grid-area: text;
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
align-self: center;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label.check>span b {
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label.check>span small {
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-chart-preview {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
#settings-page-appearance .dashboard-appearance-grid>.dashboard-widget-settings {
|
||||
margin-top: 4px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
#settings-page-appearance .refresh-settings-grid>label.check {
|
||||
grid-column: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
#settings-page-appearance .appearance-settings-grid>label {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-areas: "name" "help" "control";
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
#settings-page-appearance .appearance-settings-grid>label>span:first-child {
|
||||
align-self: start;
|
||||
}
|
||||
}
|
||||
|
||||
/* Settings navigation (0.36.3) */
|
||||
@media (min-width: 761px) {
|
||||
/* Sub-tabs are a horizontal tab bar; the vertical rail layout is for the main settings menu only. */
|
||||
#panel-settings .settings-tabs.sub-tabs {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 5px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
#panel-settings .settings-tabs.sub-tabs button {
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
padding: 7px 14px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Visual groups in the main menu: appearance / traffic / rules / observability / system / security. */
|
||||
#panel-settings #settings-tabs button:is([data-settings-tab=listeners], [data-settings-tab=policies], [data-settings-tab=logging], [data-settings-tab=administration], [data-settings-tab=certificate-api]) {
|
||||
margin-top: 7px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#panel-settings #settings-tabs button:is([data-settings-tab=listeners], [data-settings-tab=policies], [data-settings-tab=logging], [data-settings-tab=administration], [data-settings-tab=certificate-api])::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: 8px;
|
||||
left: 8px;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cache and static transformation pages (0.36.3): grouped sections, help attached to its switch. */
|
||||
#cache-form .cache-section-title {
|
||||
margin-top: 20px;
|
||||
padding-top: 14px;
|
||||
border-top: 1px solid var(--line);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#cache-form [data-cache-settings-page=general]>.cache-section-title:first-child {
|
||||
margin-top: 2px;
|
||||
padding-top: 0;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
:is(#cache-form, #transform-form)>.check:first-of-type,
|
||||
#cache-form [data-cache-settings-page=general]>.check:first-of-type {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:is(#cache-form, #transform-form) .check+.fine {
|
||||
margin: 3px 0 12px 24px;
|
||||
}
|
||||
|
||||
:is(#cache-form, #transform-form) .cache-memory-sizing .card-heading {
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
:is(#cache-form, #transform-form) .cache-memory-sizing .card-heading>h3 {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
:is(#cache-form, #transform-form) .field-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(min(100%, 210px), 1fr));
|
||||
column-gap: 14px;
|
||||
}
|
||||
|
||||
#transform-form .switch-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr));
|
||||
}
|
||||
|
||||
#cache-form #cache-default-ttl {
|
||||
display: block;
|
||||
max-width: 320px;
|
||||
}
|
||||
@@ -430,13 +430,12 @@ html[data-dashboard-density] #panel-overview .dashboard-overview-grid>.card.pool
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-left: 6px;
|
||||
padding: 1px 5px;
|
||||
padding: 2px 6px;
|
||||
border: 1px solid var(--pill-line);
|
||||
border-radius: var(--rp-radius-control, 3px);
|
||||
border-radius: var(--rp-radius-control, 0);
|
||||
color: var(--accent);
|
||||
font: 9px var(--mono);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .35px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.cache-toolbar-message {
|
||||
@@ -574,8 +573,8 @@ html[data-dashboard-density] #panel-overview .dashboard-overview-grid>.card.pool
|
||||
button.config-history-day.has-revisions {
|
||||
cursor: pointer;
|
||||
color: var(--text);
|
||||
border-color: var(--line-strong, var(--line));
|
||||
background: var(--surface, var(--bg));
|
||||
border-color: var(--line);
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
button.config-history-day.has-revisions:hover,
|
||||
@@ -834,7 +833,6 @@ html[data-table-density=ultra] .file-log-inline-detail {
|
||||
padding: 5px 7px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .mini-metrics div,
|
||||
.acl-policy-mode-card input,
|
||||
.docker-service-certificate-bar>.check>input,
|
||||
html[data-table-density=ultra] .file-log-field-grid {
|
||||
@@ -1006,7 +1004,7 @@ html[data-table-density=ultra] .file-log-inline-detail pre {
|
||||
.file-log-advanced-parser {
|
||||
margin: 0 0 1rem;
|
||||
padding: .75rem 1rem;
|
||||
border-radius: var(--rp-radius-surface, var(--radius, 12px));
|
||||
border-radius: var(--rp-radius-surface, 12px);
|
||||
}
|
||||
|
||||
.file-log-aggregate-form {
|
||||
@@ -1074,3 +1072,78 @@ html[data-table-density=ultra] .file-log-inline-detail pre {
|
||||
max-height: 68dvh;
|
||||
font: 11px/1.5 var(--mono);
|
||||
}
|
||||
|
||||
/* Cache → Domains and effectiveness (0.36.3): numeric columns aligned, outcomes coloured like the dashboard bar. */
|
||||
#cache-domain-scroll .cache-table :is(th, td):nth-child(n+3):nth-child(-n+8) {
|
||||
text-align: right;
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#cache-domain-scroll .cache-table td:first-child {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
#cache-domain-scroll .cache-table td:nth-child(2) {
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#cache-domain-scroll .cache-table tbody tr:hover {
|
||||
background: var(--panel2);
|
||||
}
|
||||
|
||||
#cache-domain-scroll .cache-table td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.cache-outcomes-cell {
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.cache-outcome-hit {
|
||||
color: var(--chart-accent);
|
||||
}
|
||||
|
||||
.cache-outcome-miss {
|
||||
color: var(--chart-secondary);
|
||||
}
|
||||
|
||||
.cache-outcome-bypass {
|
||||
color: var(--chart-tertiary);
|
||||
}
|
||||
|
||||
.cache-outcome-sep {
|
||||
margin: 0 5px;
|
||||
color: var(--muted);
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.cache-ratio-cell {
|
||||
min-width: 96px;
|
||||
}
|
||||
|
||||
.cache-ratio-value {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.cache-ratio-meter {
|
||||
display: block;
|
||||
height: 3px;
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
background: var(--line);
|
||||
}
|
||||
|
||||
.cache-ratio-meter>i {
|
||||
display: block;
|
||||
height: 100%;
|
||||
background: var(--chart-accent);
|
||||
}
|
||||
|
||||
#cache-domain-scroll .cache-reason {
|
||||
border-color: transparent;
|
||||
background: var(--panel2);
|
||||
color: var(--muted);
|
||||
}
|
||||
@@ -302,18 +302,6 @@
|
||||
max-width: calc(100vw - 12px);
|
||||
}
|
||||
|
||||
body[data-density=compact] .sidebar nav {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
body[data-density=compact] .sidebar {
|
||||
padding: 8px 9px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .topbar {
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
.sidebar .brand {
|
||||
min-width: 0;
|
||||
}
|
||||
@@ -1293,16 +1281,6 @@
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
body[data-density=compact] .docker-service-row {
|
||||
padding: 8px;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
body[data-density=compact] .docker-service-head-actions .docker-runtime .pill {
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
.backend-column-options {
|
||||
width: min(330px, calc(100vw - 32px));
|
||||
min-width: 0;
|
||||
@@ -1703,3 +1681,53 @@
|
||||
--overview-widget-placement: 1/-1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
#panel-overview .system-card .card-heading {
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 12px;
|
||||
}
|
||||
|
||||
#panel-overview .system-card .system-uptime-meta {
|
||||
white-space: normal;
|
||||
max-width: 100%;
|
||||
margin-left: auto;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
/* Docker vhosts (0.36.3): compact service rows - switch | name and details | health and actions. */
|
||||
@media (min-width:900px) {
|
||||
.docker-service-head {
|
||||
grid-template-columns: auto minmax(220px, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 6px 18px;
|
||||
}
|
||||
|
||||
.docker-service-head-actions {
|
||||
grid-column: auto;
|
||||
justify-content: flex-end;
|
||||
gap: 6px 10px;
|
||||
}
|
||||
|
||||
.docker-service-head-actions .docker-runtime {
|
||||
flex: 1 0 100%;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.docker-service-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
gap: 1px 14px;
|
||||
}
|
||||
|
||||
.docker-service-meta>b {
|
||||
flex: 0 0 100%;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.docker-service-meta>span {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
+23
-11
@@ -1821,7 +1821,7 @@
|
||||
<section class="appearance-section">
|
||||
<div class="appearance-section-heading">
|
||||
<div><span class="small-label" data-i18n="appearanceChartsSection">CHARTS</span>
|
||||
<h3 data-i18n="chartStyle">Chart style</h3>
|
||||
<h3 data-i18n="appearanceChartsTitle">Charts</h3>
|
||||
</div><button class="quiet appearance-section-reset"
|
||||
data-appearance-reset="charts" data-i18n="resetSection" type="button">Reset
|
||||
section</button>
|
||||
@@ -1840,6 +1840,14 @@
|
||||
</option>
|
||||
<option data-i18n="chartStyleWarm" value="warm">Warm</option>
|
||||
<option data-i18n="chartStyleCool" value="cool">Cool</option>
|
||||
<option data-i18n="chartStyleSunset" value="sunset">Sunset</option>
|
||||
<option data-i18n="chartStyleAurora" value="aurora">Aurora</option>
|
||||
<option data-i18n="chartStyleOcean" value="ocean">Ocean</option>
|
||||
<option data-i18n="chartStyleForest" value="forest">Forest</option>
|
||||
<option data-i18n="chartStylePastel" value="pastel">Pastel</option>
|
||||
<option data-i18n="chartStyleTerminal" value="terminal">Terminal</option>
|
||||
<option data-i18n="chartStyleBlueprint" value="blueprint">Blueprint</option>
|
||||
<option data-i18n="chartStyleColorblind" value="colorblind">Colorblind safe</option>
|
||||
</select></label>
|
||||
<label class="check appearance-chart-axes-setting"><input id="ui-chart-axes"
|
||||
type="checkbox" /><span><b data-i18n="chartAxes">Show X/Y scales on
|
||||
@@ -1864,7 +1872,7 @@
|
||||
<div class="appearance-section-heading">
|
||||
<div><span class="small-label" data-i18n="appearanceDataSection">TABLES /
|
||||
LOGS</span>
|
||||
<h3 data-i18n="tableDensity">Tables and logs density</h3>
|
||||
<h3 data-i18n="appearanceTablesTitle">Tables and logs</h3>
|
||||
</div><button class="quiet appearance-section-reset"
|
||||
data-appearance-reset="tables" data-i18n="resetSection" type="button">Reset
|
||||
section</button>
|
||||
@@ -2384,6 +2392,7 @@
|
||||
data-i18n="cacheTabDiagnostics" type="button">Static & diagnostics</button>
|
||||
</nav>
|
||||
<div data-cache-settings-page="general">
|
||||
<h3 class="subheading cache-section-title" data-i18n="cacheSectionBehavior">Behavior</h3>
|
||||
<label class="check"><input id="cache-enabled" type="checkbox" /><span
|
||||
data-i18n="enableCache">Enable shared cache</span></label>
|
||||
<p class="fine" data-i18n="cacheSafety">Only complete public-safe GET responses.
|
||||
@@ -2429,7 +2438,17 @@
|
||||
<input id="cache-varnish-grace" type="number" min="0" max="604800" step="1"
|
||||
required />
|
||||
</div>
|
||||
<div class="card soft-card cache-memory-sizing">
|
||||
<label data-i18n="cacheDefaultTtl" for="cache-default-ttl">Fallback TTL for public
|
||||
responses (0 = off)</label><input id="cache-default-ttl" max="604800" min="0"
|
||||
required="" type="number" />
|
||||
<label class="check"><input id="cache-query" type="checkbox" /><span
|
||||
data-i18n="bypassQuery">Bypass URLs with a query string</span></label>
|
||||
<label data-i18n="cachePrefixes" for="cache-prefixes">Bypass path prefixes, one per
|
||||
line</label><textarea id="cache-prefixes" placeholder="/api/private" rows="3"
|
||||
spellcheck="false"></textarea>
|
||||
|
||||
<h3 class="subheading cache-section-title" data-i18n="cacheSectionMemory">Memory and limits</h3>
|
||||
<div class="card soft-card cache-memory-sizing">
|
||||
<div class="card-heading">
|
||||
<h3 data-i18n="cacheMemorySizingTitle">Memory sizing</h3>
|
||||
<span class="pill" id="cache-memory-preset-selected">-</span>
|
||||
@@ -2483,14 +2502,7 @@
|
||||
<p class="fine" data-i18n="cacheAutoTrimHelp">When HOT memory is above the target,
|
||||
only entries idle for the configured age are removed in bounded passes. Active
|
||||
objects are not purged.</p>
|
||||
<label data-i18n="cacheDefaultTtl" for="cache-default-ttl">Fallback TTL for public
|
||||
responses (0 = off)</label><input id="cache-default-ttl" max="604800" min="0"
|
||||
required="" type="number" />
|
||||
<label class="check"><input id="cache-query" type="checkbox" /><span
|
||||
data-i18n="bypassQuery">Bypass URLs with a query string</span></label>
|
||||
<label data-i18n="cachePrefixes" for="cache-prefixes">Bypass path prefixes, one per
|
||||
line</label><textarea id="cache-prefixes" placeholder="/api/private" rows="3"
|
||||
spellcheck="false"></textarea>
|
||||
|
||||
</div>
|
||||
<div data-cache-settings-page="resilience" hidden>
|
||||
<h3 class="subheading" data-i18n="cacheCollapseTitle">Request collapsing</h3>
|
||||
|
||||
@@ -62,18 +62,19 @@
|
||||
</article>
|
||||
<article class="stat stat-with-action" data-dashboard-widget="websocket"><span data-i18n="wsActive">WebSocket
|
||||
tunnels</span><button class="pill stat-corner-action stat-corner-badge" data-i18n="tunnelsOpen"
|
||||
data-ui-icon-name="none" id="tunnels-open" type="button">Active tunnels</button><strong
|
||||
id="metric-ws">0</strong><small aria-label="Active WebSocket tunnels by frontend protocol"><span
|
||||
data-i18n="wsH1">H1
|
||||
Upgrade</span> <span id="metric-ws-h1">0</span> · <span data-i18n="wsH2Rfc8441">H2
|
||||
RFC 8441</span> <span id="metric-ws-h2">0</span> · <span data-i18n="wsH3Rfc9220">H3
|
||||
RFC 9220</span> <span id="metric-ws-h3">0</span><br><span data-i18n="wsEstablished">Established</span>:
|
||||
<span id="metric-ws-total">0</span></small></article>
|
||||
data-ui-icon-name="none" id="tunnels-open" type="button">Active tunnels</button><div class="stat-value-row"><strong
|
||||
id="metric-ws">0</strong><small class="stat-side-value" title="Established"><span
|
||||
data-i18n="wsEstablished">Established</span> <b id="metric-ws-total">0</b></small></div><small
|
||||
aria-label="Active WebSocket tunnels by frontend protocol"><span data-i18n="wsH1" title="H1 Upgrade">H1</span>
|
||||
<span id="metric-ws-h1">0</span> · <span data-i18n="wsH2Rfc8441" title="H2 RFC 8441">H2</span>
|
||||
<span id="metric-ws-h2">0</span> · <span data-i18n="wsH3Rfc9220" title="H3 RFC 9220">H3</span>
|
||||
<span id="metric-ws-h3">0</span></small></article>
|
||||
<article class="stat" data-dashboard-widget="http2"><span data-i18n="h2Requests">HTTP/2
|
||||
requests</span><strong id="metric-h2">0</strong><small><span data-i18n="h2ActiveConnections">Active H2
|
||||
requests</span><strong id="metric-h2">0</strong><small><span data-i18n="h2ActiveConnections">H2
|
||||
connections</span>: <span id="metric-h2-active">0</span></small></article>
|
||||
<article class="stat" data-dashboard-widget="http3"><span data-i18n="h3Requests">HTTP/3
|
||||
requests</span><strong id="metric-h3">0</strong></article>
|
||||
requests</span><strong id="metric-h3">0</strong><small><span data-i18n="h3ActiveConnections">H3
|
||||
connections</span>: <span id="metric-h3-active">0</span></small></article>
|
||||
<article class="stat" data-dashboard-widget="tls"><span data-i18n="tlsFailures">TLS handshake
|
||||
errors</span><strong id="metric-tls-errors">0</strong></article>
|
||||
<article class="stat stat-chart" data-dashboard-widget="http_protocol"><span data-i18n="httpProtocolMix">HTTP protocol
|
||||
|
||||
Reference in new issue
Block a user