From 48b5907f4cdee958db3997e486710a68f43b9485 Mon Sep 17 00:00:00 2001
From: th
Date: Sat, 18 Apr 2026 10:04:08 +0200
Subject: [PATCH] =?UTF-8?q?v2.0.2=20=E2=80=94=20English=20tag=20aliases,?=
=?UTF-8?q?=20English-only=20website,=20undo-body=20flaky=20fix?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- tags: accept #birthday and #appointment as English synonyms for
#geburtstag and #termin. Normalised to the German canonical form at
extractTags() write-time so every downstream check (parseTags /
calendar logic / board filters) keeps working without per-call-site
aliasing. Editor body-regex extended so the "new appointment"
heuristic and auto-sync trigger on either variant.
- website: replace #termin/#geburtstag with #appointment/#birthday in
tag chips, calendar feature list, and calendar legend.
- tests: fix flaky "Undo: Editor Save → Ctrl+Z reverts body change"
that raced doSave(). The test polled the server for the patched body
and fired Ctrl+Z as soon as it landed, but the undo shortcut is
guarded by !guards.isOpen('modal'), and closeModal() only runs after
the post-patch _reloadAll — on fast servers the key was swallowed.
Poll now also waits for the modal `.open` class to drop.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
config.php | 2 +-
electron/package.json | 2 +-
public/index.php | 9 ++++++++-
public/js/modules/editor.js | 4 ++--
public/plugins/tests/undo.test.js | 8 +++++++-
website/index.html | 12 ++++++------
6 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/config.php b/config.php
index 20f7176..8b2564b 100644
--- a/config.php
+++ b/config.php
@@ -1,7 +1,7 @@
'geburtstag', 'appointment' => 'termin'];
+ $tags = array_map(fn($t) => $aliases[$t] ?? $t, array_map('strtolower', $matches[1] ?? []));
+ return implode(',', array_unique($tags));
}
// Plugin route handlers (registered by plugin backend.php files).
diff --git a/public/js/modules/editor.js b/public/js/modules/editor.js
index bd7ebb4..9750cad 100644
--- a/public/js/modules/editor.js
+++ b/public/js/modules/editor.js
@@ -234,7 +234,7 @@ export function openModal(card = null) {
// `card` can be `null` (add-button new) or a shell `{id: null, ...}`
// from the calendar day-popup — both count as "new", so key on
// card?.id not the card ref itself.
- const isNewAppointment = !card?.id && /#(termin|geburtstag)\b/.test(body.value);
+ const isNewAppointment = !card?.id && /#(termin|appointment|geburtstag|birthday)\b/.test(body.value);
inpBucket.value = card?.bucket_id ? card.bucket_id
: (isNewAppointment ? ''
: (!virtualBuckets.includes(state.activeBucket) ? state.activeBucket : ''));
@@ -512,7 +512,7 @@ async function doSave(close, { animate = true } = {}) {
}
await window._reloadAll();
// Auto-sync if card has #termin or #geburtstag
- if (data.body && /#(termin|geburtstag)\b/.test(data.body)) {
+ if (data.body && /#(termin|appointment|geburtstag|birthday)\b/.test(data.body)) {
window._triggerSync?.();
}
if (close) {
diff --git a/public/plugins/tests/undo.test.js b/public/plugins/tests/undo.test.js
index a3aeab6..aecca9c 100644
--- a/public/plugins/tests/undo.test.js
+++ b/public/plugins/tests/undo.test.js
@@ -109,11 +109,17 @@ describe('Undo: Editor Save', () => {
bodyEl.dispatchEvent(new Event('input', { bubbles: true }));
click('#modal-save-close');
+ // Wait for both the server patch AND the modal close before firing
+ // Ctrl+Z — the global undo shortcut is guarded by
+ // `!guards.isOpen('modal')`, so if doSave's closeModal() hasn't run
+ // yet (it only fires after the post-save _reloadAll), the undo key
+ // is swallowed silently and the test races the client's save flow.
let card;
for (let i = 0; i < 40; i++) {
await sleep(100);
card = (await fetch(`api/cards?ids=${res.id}`).then(r => r.json())).find(c => c.id == res.id);
- if ((card?.body || '').includes('after edit')) break;
+ const modalClosed = !document.getElementById('modal')?.classList.contains('open');
+ if ((card?.body || '').includes('after edit') && modalClosed) break;
}
expect(card.body).toContain('after edit');
diff --git a/website/index.html b/website/index.html
index c764499..f871e50 100644
--- a/website/index.html
+++ b/website/index.html
@@ -352,10 +352,10 @@ footer {
#ops
#done
#meeting
- #termin
+ #appointment
#research
#idea
- #geburtstag
+ #birthday
#personal
@@ -407,8 +407,8 @@ See also: [[Infra checklist]]
A month-grid calendar built into hyprcrd. Journal entries, appointments, and birthdays — all just cards with the right title or tag. Bidirectional CalDAV sync with ownCloud and Nextcloud.
|