This commit is contained in:
Mateusz Gruszczyński committed 2026-11-08 12:00:38 +01:00
1 parent 3d3e0ea5b8
commit 993062520f
6 files changed
+618 -588

No files matched your search

+579 -579
View File
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -1678,6 +1678,7 @@
"dockerSearchPlaceholder": "Search service, host, alias or agent...",
"dockerShowHidden": "Show Hidden",
"dockerHideHidden": "Hide Hidden",
"dockerHideDisabled": "Hide disabled",
"dockerHideVhost": "Hide from view",
"dockerUnhideVhost": "Show in view",
"dockerCertificate": "Frontend certificate",
@@ -1733,8 +1734,8 @@
"autoIdPending": "Generated from the name",
"autoIdBadge": "auto",
"vhCertificateUncoveredPrompt": "Certificate \"{certificate}\" does not cover: {hosts}.\n\nSave anyway and force this certificate for these names? Browsers will show a name-mismatch warning. Choose Cancel to pick a matching certificate instead.",
"autoCertSniHint": "No single certificate covers all names, but each name is covered by a stored certificate. Keep \"Global SNI / default certificate\" and RustProxy will pick the right certificate for each name (SNI).",
"copyEntry": "Copy",
"autoCertSniHint": "No single certificate covers all names, but each name is covered by a stored certificate. Keep \"Global SNI / default certificate\" and RustProxy will pick the right certificate for each name (SNI).",
"autoCertHint": "Certificate \"{id}\" was selected automatically because it covers all host names. You can choose another one.",
"dockerLiveAccessLogsHelp": "Live HTTP access logs for this Docker vhost, not the container stdout/stderr.",
"networkInterfacesHistory": "Traffic by interface",
+1
View File
@@ -1678,6 +1678,7 @@
"dockerSearchPlaceholder": "Szukaj usługi, hosta, aliasu lub agenta...",
"dockerShowHidden": "Pokaż ukryte",
"dockerHideHidden": "Ukryj ukryte",
"dockerHideDisabled": "Ukryj wyłączone",
"dockerHideVhost": "Ukryj z widoku",
"dockerUnhideVhost": "Pokaż w widoku",
"dockerCertificate": "Certyfikat frontendu",
+16
View File
@@ -1779,3 +1779,19 @@
.auto-id-change { padding: 2px 8px; font-size: 11px; margin-left: auto; }
.auto-id-row[hidden], .auto-id-change[hidden], .auto-id-badge[hidden] { display: none; }
.auto-id-field input { font-family: var(--mono, monospace); font-size: 12px; }
/* Docker vhosts (post-0.36.6): section headers aligned left, hint follows the title */
.docker-service-editor>summary, .docker-health-editor>summary, .docker-acl-editor>summary,
.docker-protocol-editor>summary, .docker-timeout-editor>summary, .docker-passive-health-editor>summary {
justify-content: flex-start; text-align: left;
}
.docker-service-editor>summary>span, .docker-health-editor>summary>span, .docker-acl-editor>summary>span,
.docker-protocol-editor>summary>span, .docker-timeout-editor>summary>span, .docker-passive-health-editor>summary>span { text-align: left; }
.docker-service-editor>summary .docker-config-hint, .docker-health-editor>summary>small, .docker-acl-editor>summary>small,
.docker-protocol-editor>summary>small, .docker-timeout-editor>summary>small, .docker-passive-health-editor>summary>small {
flex: 1 1 auto; min-width: 0; text-align: left;
}
@media (min-width:721px) {
.docker-service-editor>summary>span, .docker-health-editor>summary>span, .docker-acl-editor>summary>span,
.docker-protocol-editor>summary>span, .docker-timeout-editor>summary>span, .docker-passive-health-editor>summary>span { flex: 0 0 190px; }
}
+18 -7
View File
@@ -2,7 +2,7 @@
(() => {
const sortColumns = ["service", "hostname", "status", "backend", "scheme", "published"];
let observations = [], pools = [], poolRoutes = [], poolIndex = new Map(), showHidden = false, listPrefs = { sort: "service", descending: false };
const expandedMetrics = new Set(), metricHistory = new Map();
const collapsedMetrics = new Set(), metricHistory = new Map();
function normalizeListPrefs(preferences) { return { sort: sortColumns.includes(preferences?.docker_vhost_sort) ? preferences.docker_vhost_sort : "service", descending: preferences?.docker_vhost_descending === true }; }
function syncSortDirection() { const control = $("docker-vhost-sort-direction"); if (!control) return; control.textContent = listPrefs.descending ? "↓" : "↑"; control.setAttribute("aria-label", t(listPrefs.descending ? "backendSortDescending" : "backendSortAscending")); }
function applyPreferences(preferences) { listPrefs = normalizeListPrefs(preferences); if ($("docker-vhost-sort")) $("docker-vhost-sort").value = listPrefs.sort; syncSortDirection(); applyViewFilters(); }
@@ -221,7 +221,7 @@
const section = el("details", undefined, "docker-service-editor docker-service-metrics");
section.dataset.viewKey = viewKey(agent.id, serviceKey);
section.dataset.agentId = agent.id; section.dataset.serviceKey = serviceKey;
section.open = expandedMetrics.has(section.dataset.viewKey);
section.open = !collapsedMetrics.has(section.dataset.viewKey);
const summary = el("summary"); summary.append(el("span", t("dockerTrafficStatistics"))); section.append(summary);
const grid = el("div", undefined, "vhost-live-grid"), fields = {};
for (const key of ["status", "vhRequests", "vhActive", "vhErrors", "vhLatency", "vhTraffic"]) {
@@ -237,8 +237,8 @@
svg.append(line); chart.append(svg); section.append(chart);
section.dockerMetricView = { fields, chartValue, line };
section.addEventListener("toggle", () => {
if (section.open) expandedMetrics.add(section.dataset.viewKey);
else expandedMetrics.delete(section.dataset.viewKey);
if (section.open) collapsedMetrics.delete(section.dataset.viewKey);
else collapsedMetrics.add(section.dataset.viewKey);
syncMetricsToggle();
});
return section;
@@ -516,6 +516,11 @@
}
card.hidden = rows.length ? visible === 0 : (!!query && !(card.dataset.searchText || "").includes(query));
}
const hideDisabled = $("docker-hide-disabled");
if (hideDisabled) {
const pending = [...document.querySelectorAll("#docker-discovery-list .docker-service-row")].filter(row => row.dockerSort?.published === 1 && !hiddenVhosts.has(row.dataset.viewKey)).length;
hideDisabled.disabled = pending === 0; hideDisabled.textContent = `${t("dockerHideDisabled")}${pending ? ` (${pending})` : ""}`;
}
const toggle = $("docker-show-hidden"); if (toggle) { const key = showHidden ? "dockerHideHidden" : "dockerShowHidden"; toggle.dataset.i18n = key; toggle.textContent = t(key); }
syncMetricsToggle();
}
@@ -560,8 +565,8 @@
const expand = !sections.every(section => section.open);
for (const section of sections) {
section.open = expand;
if (expand) expandedMetrics.add(section.dataset.viewKey);
else expandedMetrics.delete(section.dataset.viewKey);
if (expand) collapsedMetrics.delete(section.dataset.viewKey);
else collapsedMetrics.add(section.dataset.viewKey);
}
syncMetricsToggle();
});
@@ -570,6 +575,12 @@
$("docker-search")?.addEventListener("input", applyViewFilters);
$("docker-vhost-sort")?.addEventListener("change", event => { listPrefs.sort = event.target.value; void saveListPrefs(); applyViewFilters(); });
$("docker-vhost-sort-direction")?.addEventListener("click", () => { listPrefs.descending = !listPrefs.descending; syncSortDirection(); void saveListPrefs(); applyViewFilters(); });
$("docker-hide-disabled")?.addEventListener("click", () => {
for (const row of document.querySelectorAll("#docker-discovery-list .docker-service-row")) if (row.dockerSort?.published === 1) hiddenVhosts.add(row.dataset.viewKey);
saveHidden();
document.querySelectorAll("#docker-discovery-list .docker-view-toggle").forEach(button => { const row = button.closest(".docker-service-row"); if (row) button.textContent = t(hiddenVhosts.has(row.dataset.viewKey) ? "dockerUnhideVhost" : "dockerHideVhost"); });
applyViewFilters();
});
$("docker-show-hidden")?.addEventListener("click", () => { showHidden = !showHidden; applyViewFilters(); });
$("docker-agent-add")?.addEventListener("click", () => { const target = $("docker-agent-settings-list"); target.querySelector(".empty")?.remove(); target.append(agentSettingsRow()); setSettingsDirty("docker-agents-form"); });
$("docker-agents-form")?.addEventListener("input", () => setSettingsDirty("docker-agents-form")); $("docker-agents-form")?.addEventListener("change", () => setSettingsDirty("docker-agents-form"));
@@ -591,5 +602,5 @@
active: () => currentPanel === "docker-vhosts" && canLiveRender() && (liveEnabled() || hasUnobservedAgent()),
run: async context => refresh(false, context)
});
window.rustProxyDocker = { render() { syncLiveSwitch(); renderSettings(); renderDiscovery(); if (currentPanel === "docker-vhosts" && authenticated) { rustProxyRefresh.sync(); void rustProxyRefresh.manual("docker"); } }, refresh, renderStatus: renderDockerMetrics, applyPreferences, reset() { observations = []; pools = []; poolRoutes = []; poolIndex = new Map(); expandedMetrics.clear(); metricHistory.clear(); showHidden = false; listPrefs = { sort: "service", descending: false }; hiddenVhosts = loadHidden(); if ($("docker-search")) $("docker-search").value = ""; if ($("docker-vhost-sort")) $("docker-vhost-sort").value = listPrefs.sort; syncSortDirection(); $("docker-discovery-list")?.replaceChildren(); $("docker-agent-settings-list")?.replaceChildren(); syncLiveSwitch(); applyViewFilters(); } };
window.rustProxyDocker = { render() { syncLiveSwitch(); renderSettings(); renderDiscovery(); if (currentPanel === "docker-vhosts" && authenticated) { rustProxyRefresh.sync(); void rustProxyRefresh.manual("docker"); } }, refresh, renderStatus: renderDockerMetrics, applyPreferences, reset() { observations = []; pools = []; poolRoutes = []; poolIndex = new Map(); collapsedMetrics.clear(); metricHistory.clear(); showHidden = false; listPrefs = { sort: "service", descending: false }; hiddenVhosts = loadHidden(); if ($("docker-search")) $("docker-search").value = ""; if ($("docker-vhost-sort")) $("docker-vhost-sort").value = listPrefs.sort; syncSortDirection(); $("docker-discovery-list")?.replaceChildren(); $("docker-agent-settings-list")?.replaceChildren(); syncLiveSwitch(); applyViewFilters(); } };
})();
+2 -1
View File
@@ -628,7 +628,8 @@
data-i18n="dockerExpandAllMetrics" id="docker-metrics-toggle-all" type="button"
aria-expanded="false" disabled>Expand all statistics</button><button class="quiet"
data-i18n="dockerAgentsSettings" id="docker-settings-open" type="button">Docker agents
settings</button><button class="quiet" data-i18n="dockerShowHidden"
settings</button><button class="quiet" data-i18n="dockerHideDisabled"
id="docker-hide-disabled" type="button" disabled>Hide disabled</button><button class="quiet" data-i18n="dockerShowHidden"
id="docker-show-hidden" type="button">Show hidden</button></div>
</article>
<div class="docker-agent-observations" id="docker-discovery-list"></div>