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. --- docs/dashboard.md | 4 +++- src/api/dashboard/dashboard.html | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/dashboard.md b/docs/dashboard.md index 2bd126a..59ec847 100644 --- a/docs/dashboard.md +++ b/docs/dashboard.md @@ -371,7 +371,9 @@ dropped; what no rule covers is quarantined on the node that made it), and for a long votes are collected and how long nodes wait after a successful vote before switching (the switch delay, `switchDelay`; below a keepalive interval only with "even below a keepalive interval" ticked, the API's `?force=switchDelay`: slow nodes may then -miss the commit before the others switch, and rejoin). The answer shows below: the remake's ID, or why it was refused +miss the commit before the others switch, and rejoin), and the replay window and the +archive retention (`replayWindow`, `archiveRetention`: epochs, an age, or both; both +empty, the defaults). The answer shows below: the remake's ID, or why it was refused (and the API's override, if any). The map shows the votes as they come. ## Console 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