diff options
Diffstat (limited to 'src/api/dashboard')
| -rw-r--r-- | src/api/dashboard/dashboard.html | 32 |
1 files changed, 32 insertions, 0 deletions
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"></label> <label title="Accept a switch delay below a keepalive interval (?force=switchDelay): slow nodes may miss the commit before the others switch, and have to rejoin"><input type="checkbox" id="remake-force-switch-delay"> even below a keepalive interval</label> + <label title="How far behind a returning node may be and still have its writes carried over automatically: at most this many remakes behind, or the first it missed proposed at most this long ago (seconds, or e.g. 12h, 7d). Both empty: 1 epoch or 7 days; one given: that limit alone">replay window + <input id="remake-replay-epochs" size="3" inputmode="numeric" placeholder="1"> epochs or + <input id="remake-replay-age" size="5" placeholder="7d"></label> + <label title="How long nodes keep the old document: this many epochs, or this long (seconds, or e.g. 12h, 30d). Both empty: 2 epochs or 30 days; one given: that limit alone">archive retention + <input id="remake-archive-epochs" size="3" inputmode="numeric" placeholder="2"> epochs or + <input id="remake-archive-age" size="5" placeholder="30d"></label> <p class="note">Writes made meanwhile that no rule covers are quarantined on the node that made them.</p> <div class="actions"><button type="submit" class="toggle">propose</button> @@ -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 { |
