aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api/dashboard/dashboard.html32
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 {