feat: free-text timestamps instead of datetime pickers

Users wanted to type things like "unbekannt" or comments for the date
fields. Start/End are now plain text inputs (max 120 chars) and are
stored/displayed verbatim - no Date parsing, no formatting. Existing
records that contain ISO strings keep working: they render exactly as
stored and refill the edit form unchanged. Also removes a duplicated
block in setup() that had slipped in earlier (double reload/flash).

Verified: node --check, no datetime-local/Date-parsing remnants,
crypto roundtrip with free-text and legacy ISO timestamps, pytest 3/3.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
This commit is contained in:
2026-10-11 00:58:19 +02:00
parent 8d488f44ff
commit c82de902a8
2 changed files with 17 additions and 19 deletions
+6 -4
View File
@@ -92,11 +92,13 @@
<label>Person B <label>Person B
<input id="f-personb" type="text" required maxlength="120" /> <input id="f-personb" type="text" required maxlength="120" />
</label> </label>
<label>Start (optional) <label>Start (optional, beliebiger Text)
<input id="f-tsstart" type="datetime-local" /> <input id="f-tsstart" type="text" maxlength="120"
placeholder="z. B. 12.03.2026, Sommer 2025, unbekannt …" />
</label> </label>
<label>Ende (optional) <label>Ende (optional, beliebiger Text)
<input id="f-tsend" type="datetime-local" /> <input id="f-tsend" type="text" maxlength="120"
placeholder="z. B. laufend, unbekannt, März 2026 …" />
</label> </label>
<label>Aktion <label>Aktion
<input id="f-action" type="text" required maxlength="500" /> <input id="f-action" type="text" required maxlength="500" />
+11 -15
View File
@@ -91,10 +91,10 @@ async function api(path, opts = {}) {
// ---------- rendering ---------- // ---------- rendering ----------
function iso(ts) { // Timestamps are free text now ("unknown", "Sommer 2025", …). Display
if (ts === null || ts === "") return "–"; // them verbatim; nothing to parse or format.
const d = new Date(ts); function showTs(value) {
return isNaN(d) ? String(ts) : d.toLocaleString(); return (value === null || value === undefined || value === "") ? "–" : String(value);
} }
function renderRow(record, payload) { function renderRow(record, payload) {
@@ -102,8 +102,8 @@ function renderRow(record, payload) {
const cells = [ const cells = [
payload.personA, payload.personA,
payload.personB, payload.personB,
iso(payload.tsStart), showTs(payload.tsStart),
iso(payload.tsEnd), showTs(payload.tsEnd),
payload.action, payload.action,
]; ];
for (const text of cells) { for (const text of cells) {
@@ -162,8 +162,8 @@ function openEditor(record, payload) {
$("#editor-title").textContent = "Datensatz bearbeiten"; $("#editor-title").textContent = "Datensatz bearbeiten";
$("#f-persona").value = payload.personA ?? ""; $("#f-persona").value = payload.personA ?? "";
$("#f-personb").value = payload.personB ?? ""; $("#f-personb").value = payload.personB ?? "";
$("#f-tsstart").value = payload.tsStart ? new Date(payload.tsStart).toISOString().slice(0, 16) : ""; $("#f-tsstart").value = payload.tsStart ?? "";
$("#f-tsend").value = payload.tsEnd ? new Date(payload.tsEnd).toISOString().slice(0, 16) : ""; $("#f-tsend").value = payload.tsEnd ?? "";
$("#f-action").value = payload.action ?? ""; $("#f-action").value = payload.action ?? "";
$("#editor-backdrop").hidden = false; $("#editor-backdrop").hidden = false;
} }
@@ -184,9 +184,9 @@ function closeEditor() {
} }
function tsOrNull(inputValue) { function tsOrNull(inputValue) {
if (!inputValue) return null; // Free-text field: trim to null or the plain string.
const d = new Date(inputValue); const v = inputValue.trim();
return isNaN(d) ? null : d.toISOString(); return v === "" ? null : v;
} }
// ---------- record operations ---------- // ---------- record operations ----------
@@ -275,10 +275,6 @@ async function setup(ev) {
resetSession(); resetSession();
return; return;
} }
$("#passphrase").value = "";
$("#setup").hidden = true;
$("#app").hidden = false;
await reload();
$("#setup-pass1").value = ""; $("#setup-pass1").value = "";
$("#setup-pass2").value = ""; $("#setup-pass2").value = "";
$("#setup").hidden = true; $("#setup").hidden = true;