v0.25.4
This commit is contained in:
1 parent
e6604e41fc
commit
1dea7f55c8
49 files changed
+4499
-4025
No files matched your search
@@ -1,4 +1,4 @@
|
||||
let configHistoryEntries = [];
|
||||
let configHistoryEntries = [], configHistorySelectedRevision = null;
|
||||
function historyDate(value, options = {}) {
|
||||
try { return new Intl.DateTimeFormat(locale(), options).format(new Date(Number(value) * 1000)); }
|
||||
catch { return new Date(Number(value) * 1000).toLocaleString(); }
|
||||
@@ -13,6 +13,12 @@ function historyValue(value) {
|
||||
const text = JSON.stringify(value, null, 2);
|
||||
return text.length > 6000 ? `${text.slice(0, 6000)}\n...` : text;
|
||||
}
|
||||
function syncConfigHistoryRestoreButton() {
|
||||
const button = $("config-history-restore"), revision = Number(configHistorySelectedRevision);
|
||||
if (!button) return;
|
||||
button.hidden = configHistorySelectedRevision === null;
|
||||
button.disabled = busy || !envelope || !Number.isSafeInteger(revision) || revision >= Number(envelope.revision);
|
||||
}
|
||||
function configDiff(before, after, path = "$", output = [], depth = 0) {
|
||||
if (output.length >= 200) return output;
|
||||
if (Object.is(before, after)) return output;
|
||||
@@ -29,8 +35,10 @@ function configDiff(before, after, path = "$", output = [], depth = 0) {
|
||||
function renderConfigRevisionDetail(detail) {
|
||||
const entry = detail?.revision;
|
||||
if (!entry) return;
|
||||
configHistorySelectedRevision = Number(entry.revision);
|
||||
$("config-history-detail-title").textContent = `${t("configHistoryRevision")} ${entry.revision}`;
|
||||
$("config-history-detail-meta").textContent = `${historyDate(entry.time, { dateStyle: "medium", timeStyle: "short" })} · ${entry.actor}`;
|
||||
syncConfigHistoryRestoreButton();
|
||||
document.querySelectorAll(".config-history-revision").forEach(button => button.classList.toggle("active", Number(button.dataset.revision) === Number(entry.revision)));
|
||||
const diff = configDiff(entry.previous_config, entry.config);
|
||||
const box = $("config-history-diff"); box.replaceChildren();
|
||||
@@ -95,7 +103,29 @@ function renderConfigHistory() {
|
||||
}
|
||||
if (!months.length) calendar.append(el("p", t("configHistoryEmpty"), "empty"));
|
||||
}
|
||||
async function restoreConfigRevision() {
|
||||
const revision = Number(configHistorySelectedRevision);
|
||||
if (!envelope || busy || !Number.isSafeInteger(revision) || revision >= Number(envelope.revision)) return;
|
||||
const expectedRevision = Number(envelope.revision);
|
||||
const message = t("configHistoryRestoreConfirm").replace("{revision}", revision).replace("{current}", expectedRevision);
|
||||
if (!(await appConfirm(message, { danger: true, confirmLabel: t("configHistoryRestoreAction") }))) return;
|
||||
const button = $("config-history-restore"), epoch = authEpoch;
|
||||
busy = true; syncConfigHistoryRestoreButton();
|
||||
try {
|
||||
const value = await api("/api/config/history/restore", { method: "POST", body: JSON.stringify({ revision, expected_revision: expectedRevision }) });
|
||||
if (!authenticated || epoch !== authEpoch) return;
|
||||
envelope = value;
|
||||
await refreshCertificateInventory();
|
||||
if (!authenticated || epoch !== authEpoch) return;
|
||||
renderConfig();
|
||||
toast(t("configHistoryRestored").replace("{revision}", revision).replace("{new_revision}", value.revision));
|
||||
await refresh(true);
|
||||
if (authenticated && epoch === authEpoch) await loadConfigHistory();
|
||||
} catch (error) { toast(error.message, true); if (error.status === 401) lock(); }
|
||||
finally { busy = false; if (button?.isConnected) syncConfigHistoryRestoreButton(); }
|
||||
}
|
||||
async function loadConfigHistory() {
|
||||
configHistorySelectedRevision = null; syncConfigHistoryRestoreButton();
|
||||
$("config-history-summary").textContent = t("configHistoryLoading");
|
||||
try {
|
||||
const result = await api("/api/config/history?limit=512"); configHistoryEntries = result.revisions || []; renderConfigHistory();
|
||||
@@ -105,3 +135,4 @@ async function loadConfigHistory() {
|
||||
$("config-history-open").addEventListener("click", () => { const dialog = $("config-history-dialog"); if (!dialog.open) dialog.showModal(); void loadConfigHistory(); });
|
||||
$("config-history-close").addEventListener("click", () => $("config-history-dialog").close());
|
||||
$("config-history-reload").addEventListener("click", () => void loadConfigHistory());
|
||||
$("config-history-restore").addEventListener("click", () => void restoreConfigRevision());
|
||||
@@ -6,7 +6,7 @@ function renderSettings() {
|
||||
if (!settingsDirty.has("response-form")) {
|
||||
const server = config.server_header || {}, compression = config.compression || {}, diagnostics = config.diagnostic_headers || {};
|
||||
$("expose-request-id").checked = !!diagnostics.request_id;
|
||||
$("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.25.3";
|
||||
$("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.25.4";
|
||||
for (const name of ["gzip", "br", "zstd", "deflate"]) $(`compress-${name}`).checked = !!compression[name];
|
||||
$("compress-min").value = compression.min_bytes ?? 1024; syncServerMode();
|
||||
}
|
||||
|
||||
@@ -1472,7 +1472,7 @@
|
||||
<option data-i18n="serverCustom" value="custom">Replace / add custom value</option>
|
||||
</select>
|
||||
<label data-i18n="serverValue" for="server-value">Custom Server value</label><input
|
||||
id="server-value" maxlength="256" placeholder="RustProxy/v0.25.3"
|
||||
id="server-value" maxlength="256" placeholder="RustProxy/v0.25.4"
|
||||
spellcheck="false" />
|
||||
<h3 class="subheading" data-i18n="diagnosticHeaders">Diagnostic headers</h3>
|
||||
<div class="switch-grid">
|
||||
@@ -2218,7 +2218,7 @@
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
<footer class="page-footer"><span>RustProxy <b>0.25.3</b></span><span id="footer-status">API - /
|
||||
<footer class="page-footer"><span>RustProxy <b>0.25.4</b></span><span id="footer-status">API - /
|
||||
dropped: 0</span></footer>
|
||||
</div>
|
||||
</main>
|
||||
@@ -2370,7 +2370,7 @@
|
||||
<aside class="card config-history-detail">
|
||||
<div class="config-history-detail-head">
|
||||
<div><span class="small-label" data-i18n="configHistoryChanges">CHANGES</span><h3 id="config-history-detail-title">-</h3></div>
|
||||
<span class="fine" id="config-history-detail-meta"></span>
|
||||
<div class="config-history-detail-actions"><span class="fine" id="config-history-detail-meta"></span><button class="outline" data-i18n="configHistoryRestoreAction" id="config-history-restore" type="button" hidden disabled>Restore revision</button></div>
|
||||
</div>
|
||||
<div class="config-history-revisions" id="config-history-revisions"></div>
|
||||
<div class="config-history-diff" id="config-history-diff"><p class="empty" data-i18n="configHistorySelectDay">Select a day.</p></div>
|
||||
|
||||
@@ -7734,6 +7734,18 @@ button.config-history-day.is-selected {
|
||||
margin: 3px 0 0;
|
||||
}
|
||||
|
||||
.config-history-detail-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 7px;
|
||||
align-items: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.config-history-detail-actions button {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.config-history-revisions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -7788,4 +7800,6 @@ button.config-history-day.is-selected {
|
||||
.config-history-layout { grid-template-columns: 1fr; overflow: auto; }
|
||||
.config-history-browser, .config-history-detail { overflow: visible; }
|
||||
.config-history-change-values { grid-template-columns: 1fr; }
|
||||
.config-history-detail-head { flex-direction: column; }
|
||||
.config-history-detail-actions { align-items: flex-start; text-align: left; }
|
||||
}
|
||||
Reference in new issue
Block a user