This commit is contained in:
Mateusz Gruszczyński committed 2026-10-10 23:41:54 +02:00
1 parent 24af7478b8
commit 0facfe6f5c
44 files changed
+898 -321

No files matched your search

+9 -7
View File
@@ -46,14 +46,16 @@
interception.append(toggle, codesLabel, hint); parent.append(interception);
const errors = errorsEditor(parent, values.errors);
parent.append(label("p", "pagesSafetyHint", "fine"));
return { read: () => {
const selectedTokens = enabled.checked ? statuses.value.split(/[\s,]+/).filter(Boolean) : [];
const selected = selectedTokens.map(Number);
if (enabled.checked && (!selected.length || selectedTokens.some(token => !/^\d{3}$/.test(token)) || selected.length > codes.length || new Set(selected).size !== selected.length || selected.some(code => !codes.includes(code)))) {
throw new Error(t("vhostInterceptOriginInvalid"));
return {
read: () => {
const selectedTokens = enabled.checked ? statuses.value.split(/[\s,]+/).filter(Boolean) : [];
const selected = selectedTokens.map(Number);
if (enabled.checked && (!selected.length || selectedTokens.some(token => !/^\d{3}$/.test(token)) || selected.length > codes.length || new Set(selected).size !== selected.length || selected.some(code => !codes.includes(code)))) {
throw new Error(t("vhostInterceptOriginInvalid"));
}
return { response: response.read(), fallback: fallback.read(), errors: errors.read(), intercept_statuses: selected };
}
return { response: response.read(), fallback: fallback.read(), errors: errors.read(), intercept_statuses: selected };
} };
};
}
let global = null;
function render() { if (!envelope || settingsDirty.has("pages-form")) return; const values = envelope.config.pages || {}, parent = $("global-pages-fields"); parent.replaceChildren(); const ip = pageEditor(parent, "pageDirectIp", values.direct_ip), unknown = pageEditor(parent, "pageUnknownHost", values.unknown_host), errors = errorsEditor(parent, values.errors); global = { read: () => ({ direct_ip: ip.read(), unknown_host: unknown.read(), errors: errors.read() }) }; }
+2 -2
View File
@@ -214,7 +214,7 @@ curl --fail --show-error --request POST \
$("admin-certificate").replaceChildren(generated, ...(envelope.config.tls?.certificates || []).map(cert => { const o = document.createElement("option"); o.value = cert.id; o.textContent = cert.id; return o; })); $("admin-certificate").value = current;
$("admin-hosts").value = (admin.allowed_hosts || []).join("\n");
$("admin-session-days").value = Number(admin.session_days || 30);
for (const codec of ["zstd", "br", "gzip"]) $( `admin-compression-${codec}` ).checked = admin.panel_compression?.[codec] !== false;
for (const codec of ["zstd", "br", "gzip"]) $(`admin-compression-${codec}`).checked = admin.panel_compression?.[codec] !== false;
}
const listenLocked = !!adminStatus?.listen_locked;
$("admin-listen").disabled = listenLocked; $("admin-listen-lock-note").hidden = !listenLocked;
@@ -300,7 +300,7 @@ curl --fail --show-error --request POST \
}, "prometheus");
bindSettingsForm("administration-form", next => {
const locked = !!latestStatus?.administration?.listen_locked;
next.administration = { listen: locked ? null : $("admin-listen").value.trim(), tls: $("admin-tls").checked, certificate_id: $("admin-tls").checked ? ($("admin-certificate").value || null) : null, allowed_hosts: $("admin-hosts").value.split(/[\n,]+/).map(v => v.trim()).filter(Boolean), session_days: Number($("admin-session-days").value), panel_compression: Object.fromEntries(["zstd", "br", "gzip"].map(codec => [codec, $( `admin-compression-${codec}` ).checked])) };
next.administration = { listen: locked ? null : $("admin-listen").value.trim(), tls: $("admin-tls").checked, certificate_id: $("admin-tls").checked ? ($("admin-certificate").value || null) : null, allowed_hosts: $("admin-hosts").value.split(/[\n,]+/).map(v => v.trim()).filter(Boolean), session_days: Number($("admin-session-days").value), panel_compression: Object.fromEntries(["zstd", "br", "gzip"].map(codec => [codec, $(`admin-compression-${codec}`).checked])) };
}, "administration");
bindSettingsForm("tls-policy-form", next => {
if (!$("tls-policy-12").checked && !$("tls-policy-13").checked) throw fieldError($("tls-policy-12"), t("tlsPolicyVersionRequired"));
+93 -25
View File
@@ -252,15 +252,21 @@ html.app-startup-failed .app-startup-recovery {
}
@keyframes app-startup-spin {
to { transform: rotate(360deg) }
to {
transform: rotate(360deg)
}
}
@keyframes app-startup-reveal {
to { visibility: visible }
to {
visibility: visible
}
}
@media (prefers-reduced-motion: reduce) {
.app-startup-spinner { animation: none }
.app-startup-spinner {
animation: none
}
}
body {
@@ -5416,7 +5422,9 @@ dialog .window-heading {
}
@media (max-width: 650px) {
.vh-www-pair-directions { grid-template-columns: minmax(0, 1fr) }
.vh-www-pair-directions {
grid-template-columns: minmax(0, 1fr)
}
}
.vh-www-choice {
@@ -7701,9 +7709,17 @@ body[data-density="compact"] .page-footer {
}
/* The legend keys must use the same theme/preset palette as the SVG strokes. */
.stat-chart .stat-chart-legend .legend-h1 i { background: var(--traffic-h1); }
.stat-chart .stat-chart-legend .legend-h2 i { background: var(--traffic-h2); }
.stat-chart .stat-chart-legend .legend-h3 i { background: var(--traffic-h3); }
.stat-chart .stat-chart-legend .legend-h1 i {
background: var(--traffic-h1);
}
.stat-chart .stat-chart-legend .legend-h2 i {
background: var(--traffic-h2);
}
.stat-chart .stat-chart-legend .legend-h3 i {
background: var(--traffic-h3);
}
.stat-chart .stat-chart-legend b {
font-family: var(--mono);
@@ -9946,6 +9962,7 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
width: 100%
}
}
.listener-active-summary {
margin-top: 10px;
padding: 10px 12px;
@@ -10002,7 +10019,7 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
margin-top: 10px
}
.location-header-editor .vh-header-rule-head > button {
.location-header-editor .vh-header-rule-head>button {
margin-left: auto;
flex: 0 0 auto
}
@@ -10013,7 +10030,6 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
}
}
/* 0.29.7: PHP-FPM local/profile toggle rows with accessible info popovers. */
.php-switch-row {
display: flex;
align-items: center;
@@ -10023,6 +10039,7 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
min-height: 30px;
margin: 4px 0;
}
.php-switch-row .php-switch-label {
display: inline-flex !important;
flex: 0 1 auto;
@@ -10032,14 +10049,26 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
margin: 0 !important;
line-height: 1.5;
}
.php-switch-row .php-switch-label input[type="checkbox"] {
position: static;
flex: 0 0 var(--ui-check-size);
margin: 0;
}
.php-switch-row .php-switch-label span { min-width: 0; }
.php-switch-row .php-field-info { flex: 0 0 auto; }
.php-switch-row .php-field-info .metric-info-popover { right: auto; left: 0; }
.php-switch-row .php-switch-label span {
min-width: 0;
}
.php-switch-row .php-field-info {
flex: 0 0 auto;
}
.php-switch-row .php-field-info .metric-info-popover {
right: auto;
left: 0;
}
.php-reference pre {
overflow-x: auto;
white-space: pre;
@@ -10049,6 +10078,7 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
background: var(--panel2);
font: 12px/1.6 var(--mono);
}
.php-profile-help-divider {
width: 100%;
height: 0;
@@ -10056,12 +10086,27 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
border: 0;
border-top: 1px solid var(--line);
}
.php-origin-errors { grid-column: 1 / -1; display: grid; gap: 8px; padding: 10px 0; border-top: 1px solid var(--line); }
.php-origin-errors > label { max-width: 430px; }
.php-origin-errors > .check { margin: 0 !important; }
.php-origin-errors .fine { margin: 0; }
/* Keep the Overview refresh action on the same row as the page title. */
.php-origin-errors {
grid-column: 1 / -1;
display: grid;
gap: 8px;
padding: 10px 0;
border-top: 1px solid var(--line);
}
.php-origin-errors>label {
max-width: 430px;
}
.php-origin-errors>.check {
margin: 0 !important;
}
.php-origin-errors .fine {
margin: 0;
}
.page-intro-copy,
.page-intro-title-row {
min-width: 0;
@@ -10090,30 +10135,47 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
font-size: clamp(18px, 5vw, 24px);
letter-spacing: -.6px
}
.page-intro-title-row .overview-refresh {
padding: 7px 9px;
font-size: 11px
}
}
/* Keep the system API indicator next to its action, aligned as one unit. */
.system-info-heading-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; flex-shrink: 0; }
.system-info-heading-actions .pill { white-space: nowrap; }
.system-info-heading-actions {
display: flex;
align-items: center;
gap: 8px;
margin-left: auto;
flex-shrink: 0;
}
.system-info-heading-actions .pill {
white-space: nowrap;
}
/* Contextual, keyboard-accessible curl examples next to the cache allowlist. */
.cache-maintenance-help {
display: flex;
align-items: center;
gap: 8px;
position: relative;
}
.cache-maintenance-help .subheading { margin: 0; }
.cache-maintenance-info { position: static; flex-shrink: 0; }
.cache-maintenance-help .subheading {
margin: 0;
}
.cache-maintenance-info {
position: static;
flex-shrink: 0;
}
.cache-maintenance-info .metric-info-popover {
max-height: min(60vh, 420px);
overflow-y: auto;
width: min(440px, calc(100vw - 56px));
}
.cache-maintenance-info .metric-info-popover code {
display: block;
white-space: pre-wrap;
@@ -10122,5 +10184,11 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
font-size: 11px;
line-height: 1.55;
}
.cache-maintenance-info .metric-info-popover .fine + code { margin-top: 6px; }
.cache-maintenance-info .metric-info-popover code + .fine { margin-top: 8px; }
.cache-maintenance-info .metric-info-popover .fine+code {
margin-top: 6px;
}
.cache-maintenance-info .metric-info-popover code+.fine {
margin-top: 8px;
}