fix: keep routing edits during refresh

This commit is contained in:
Андрей Бобырев
2026-06-06 15:25:26 +03:00
parent ca12617a08
commit b5360aa2e1
2 changed files with 40 additions and 6 deletions

View File

@@ -532,6 +532,8 @@ const state = {
userTrafficLoading: false,
backupSchedule: null,
routing: null,
routingDirty: false,
routingPreviewMap: null,
warp: null,
qrLink: "",
pendingUsers: new Set(),
@@ -656,7 +658,10 @@ function applyI18n() {
$("#languageSelect").value = state.lang;
$("#settingsLanguage").textContent = state.lang === "ru" ? "Русский" : "English";
$("#settingsTheme").textContent = state.theme === "dark" ? t("darkTheme") : t("lightTheme");
$("#visualTitle").textContent = t("visualTitle");
const visualPort = state.routingDirty
? (state.routingPreviewMap?.public_port || $("#visualRoutingPort")?.value || state.routing?.port || 443)
: (state.overview?.port_map?.public_port || state.routing?.port || 443);
$("#visualTitle").textContent = t("visualTitle").replace("{port}", visualPort);
$("#visualText").textContent = t("visualText");
updateTrafficControls();
updateUserTrafficControls();
@@ -921,7 +926,11 @@ function renderOverview() {
$("#settingsBind").textContent = `${bind.host || "127.0.0.1"}:${bind.port || 1984}`;
$("#metricMode").textContent = cfg.mode || "--";
renderSiteStatus();
renderPortMap(data.port_map || data.port_443 || {});
if (state.routingDirty && state.routingPreviewMap) {
renderPortMap(state.routingPreviewMap);
} else if (!state.routingDirty) {
renderPortMap(data.port_map || data.port_443 || {});
}
$("#metricUsers").textContent = data.users_count ?? 0;
$("#metricProxyTraffic").textContent = fmtBytes(stats.proxy_bytes);
$("#metricProxyPackets").textContent = `${stats.proxy_pkts || 0} ${t("packets")}`;
@@ -1458,12 +1467,29 @@ function routingControlPairs() {
}
function setRoutingControlValues(routing = {}) {
if (state.routingDirty) return;
routingControlPairs().forEach((item) => {
if (document.activeElement === item.port || document.activeElement === item.mask) return;
item.port.value = routing.port || 443;
item.mask.value = routing.mask_host || "google.com";
});
}
function syncRoutingControls(source) {
const form = source?.closest?.("form");
const port = form?.querySelector('[name="port"]')?.value ?? "";
const mask = form?.querySelector('[name="mask_host"]')?.value ?? "";
routingControlPairs().forEach((item) => {
if (item.port !== source && document.activeElement !== item.port) item.port.value = port;
if (item.mask !== source && document.activeElement !== item.mask) item.mask.value = mask;
});
}
function markRoutingDirty(eventObj) {
state.routingDirty = true;
syncRoutingControls(eventObj.target);
}
function setRoutingNotes(routing = {}) {
const conflicts = routing.conflicts || [];
const message = routingSummary(routing);
@@ -1476,6 +1502,7 @@ function setRoutingNotes(routing = {}) {
function renderRoutingSettings(payload = null) {
const routing = payload || state.routing || state.overview?.routing || {};
if (state.routingDirty && !payload) return;
if (!payload) {
setRoutingControlValues(routing);
}
@@ -1679,14 +1706,15 @@ async function checkRoutingPort(inputEl = $("#routingPort")) {
try {
const data = await api(`/api/routing?port=${encodeURIComponent(port)}`);
renderRoutingSettings(data);
renderPortMap({
state.routingPreviewMap = {
public_port: data.port,
configured_port: state.routing?.port || state.overview?.routing?.port || data.port,
listeners: data.listeners || [],
routes: [],
ok: data.ok,
error: data.error,
});
};
renderPortMap(state.routingPreviewMap);
} catch (err) {
$("#routingStatus").textContent = t("routingBusy");
$("#routingStatus").className = "status-pill health-error";
@@ -1714,6 +1742,8 @@ async function saveRoutingSettings(eventObj) {
method: "POST",
body: JSON.stringify(payload),
});
state.routingDirty = false;
state.routingPreviewMap = null;
state.routing = data;
state.overview = await api("/api/overview");
renderRoutingSettings();
@@ -1997,8 +2027,12 @@ $("#repairStatsBtn").addEventListener("click", repairStats);
$("#collectStatsBtn").addEventListener("click", collectStats);
$("#authSettingsForm").addEventListener("submit", updateAuthSettings);
$("#visualRoutingForm").addEventListener("submit", saveRoutingSettings);
$("#visualRoutingPort").addEventListener("input", markRoutingDirty);
$("#visualRoutingMaskHost").addEventListener("input", markRoutingDirty);
$("#visualRoutingPort").addEventListener("change", (eventObj) => checkRoutingPort(eventObj.target));
$("#routingSettingsForm").addEventListener("submit", saveRoutingSettings);
$("#routingPort").addEventListener("input", markRoutingDirty);
$("#routingMaskHost").addEventListener("input", markRoutingDirty);
$("#routingPort").addEventListener("change", (eventObj) => checkRoutingPort(eventObj.target));
$("#warpSettingsForm").addEventListener("submit", saveWarpSettings);
$("#warpScope").addEventListener("change", renderWarpSettings);

View File

@@ -11,7 +11,7 @@
document.documentElement.dataset.theme = theme;
}());
</script>
<link rel="stylesheet" href="/styles.css?v=2.5.0-admin24">
<link rel="stylesheet" href="/styles.css?v=2.5.0-admin25">
</head>
<body>
<div class="app-shell">
@@ -482,6 +482,6 @@
<button id="qrCopyBtn" type="button" class="soft" data-i18n="copyLink">Copy link</button>
</div>
</div>
<script src="/app.js?v=2.5.0-admin24" type="module"></script>
<script src="/app.js?v=2.5.0-admin25" type="module"></script>
</body>
</html>