From b52d4b6181e7fcf806a655d218e74de71b54cbf8 Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 9 Nov 2026 03:23:10 +0000 Subject: dashboard: the replay window and archive retention in the remake dialog The remake dialog set the kind, its input, the settle time and the switch delay, but not the replay window or the archive retention. Now each has two fields, epochs and an age, their defaults as placeholders: both empty sends nothing (the node's defaults), one given sends that limit alone, as the API reads it; in the body, or for an import in the query (`replayWindow`, `archiveRetention`). Epochs that aren't a whole number are refused in the page. --- src/api/dashboard/dashboard.html | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'src/api') diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html index d173418..dbf5480 100644 --- a/src/api/dashboard/dashboard.html +++ b/src/api/dashboard/dashboard.html @@ -418,6 +418,12 @@ title="How long nodes wait after the vote succeeded before switching, so the commit reaches every node first: seconds, or e.g. 500ms, 1m; empty: one keepalive interval"> + +

Writes made meanwhile that no rule covers are quarantined on the node that made them.

@@ -4160,6 +4166,20 @@ document.getElementById("remake-json-file").addEventListener("change", event => file.text().then(text => { document.getElementById("remake-json").value = text; }) .catch(error => remakeResult("Reading " + file.name + ": " + error, true)); }); +// A retention from its two fields (`epochs` and `age`), or null for the node's default +// (both empty); throws where the epochs aren't a whole number. +function remakeRetention(name, label) { + const epochs = document.getElementById("remake-" + name + "-epochs").value.trim(); + const age = document.getElementById("remake-" + name + "-age").value.trim(); + if (!epochs && !age) return null; + const retention = {}; + if (epochs) { + if (!/^\d+$/.test(epochs)) throw new Error("The " + label + "'s epochs aren't a whole number."); + retention.epochs = Number(epochs); + } + if (age) retention.age = age; + return retention; +} remakeForm.addEventListener("submit", event => { event.preventDefault(); const kind = document.getElementById("remake-kind").value; @@ -4167,6 +4187,14 @@ remakeForm.addEventListener("submit", event => { const switchDelay = document.getElementById("remake-switch-delay").value.trim(); const force = document.getElementById("remake-force-switch-delay").checked ? "force=switchDelay" : ""; + let replayWindow, archiveRetention; + try { + replayWindow = remakeRetention("replay", "replay window"); + archiveRetention = remakeRetention("archive", "archive retention"); + } catch (error) { + remakeResult(error.message, true); + return; + } let request; if (kind === "import") { // The document as it is (octet-stream): its options in the query. @@ -4175,6 +4203,8 @@ remakeForm.addEventListener("submit", event => { const options = new URLSearchParams(force); if (settle) options.set("settle", settle); if (switchDelay) options.set("switchDelay", switchDelay); + if (replayWindow) options.set("replayWindow", JSON.stringify(replayWindow)); + if (archiveRetention) options.set("archiveRetention", JSON.stringify(archiveRetention)); const rules = remakeRules(); if (rules.length) options.set("rules", JSON.stringify(rules)); const query = options.size ? "?" + options : ""; @@ -4184,6 +4214,8 @@ remakeForm.addEventListener("submit", event => { const body = { kind }; if (settle) body.settle = settle; if (switchDelay) body.switchDelay = switchDelay; + if (replayWindow) body.replayWindow = replayWindow; + if (archiveRetention) body.archiveRetention = archiveRetention; if (kind === "replace") { let parsed; try { -- cgit v1.3.1