[feat](trx-frontend-http): per-entry interleave time in TimeSpan scheduler

Each ScheduleEntry can now carry its own interleave_min, overriding the
config-level default for that slot in the cycle.  The cycle length is the
sum of all active entries' effective durations (weighted), so entries with
longer individual interleave times occupy proportionally more time.

UI: "Interleave (min, optional)" input in the add-entry form; value shown
in the entries table (displays "—" when using the config default).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-03-10 23:35:52 +01:00
parent 998c6ad0e6
commit e4cfd35282
3 changed files with 35 additions and 7 deletions
@@ -277,11 +277,13 @@
: [];
entries.forEach(function (entry, idx) {
const tr = document.createElement("tr");
const il = entry.interleave_min ? String(entry.interleave_min) + " min" : "—";
tr.innerHTML =
'<td>' + minToHHMM(entry.start_min) + '</td>' +
'<td>' + minToHHMM(entry.end_min) + '</td>' +
'<td>' + bmName(entry.bookmark_id) + '</td>' +
'<td>' + escHtml(entry.label || "") + '</td>' +
'<td>' + il + '</td>' +
'<td><button class="sch-write sch-remove-btn" data-idx="' + idx + '" type="button">Remove</button></td>';
tbody.appendChild(tr);
});
@@ -330,12 +332,15 @@
const endEl = document.getElementById("scheduler-ts-end");
const bmEl = document.getElementById("scheduler-ts-bookmark");
const labelEl = document.getElementById("scheduler-ts-label");
const ilEl = document.getElementById("scheduler-ts-entry-interleave");
if (!startEl || !endEl || !bmEl) return;
const startMin = hhmmToMin(startEl.value);
const endMin = hhmmToMin(endEl.value);
const bmId = bmEl.value;
const label = labelEl ? labelEl.value.trim() : "";
const ilVal = ilEl ? parseInt(ilEl.value, 10) : NaN;
const entryInterleave = !isNaN(ilVal) && ilVal > 0 ? ilVal : null;
if (!bmId) {
alert("Please select a bookmark.");
@@ -354,12 +359,14 @@
end_min: endMin,
bookmark_id: bmId,
label: label || null,
interleave_min: entryInterleave,
});
startEl.value = "";
endEl.value = "";
bmEl.value = ""; // reset select to first option
bmEl.value = "";
if (labelEl) labelEl.value = "";
if (ilEl) ilEl.value = "";
renderTimespanEntries();
}