fixes: scratchpad, zen ESC, chat time, tooltip safety, collab sync race
- Scratchpad: card-scoped private notes in editor (toggle vs preview), smaller font, cleared via button, stored in cards.scratchpad - Zen mode: ESC exits zen before closing detail, Z toggles zen - Chat: always show absolute time (hh:mm, yesterday, or date+time) - Backspace/Delete also deletes focused card (not just selected) - Selected + focused cards use brand accent (not accent2) - Tooltip: guard against non-element targets - Collab sync: skip poll while editor is open, 2s push debounce - Rrule test: only check geburtstag tag, not title format Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
2169c1de1b
commit
7e2b130434
11 files changed
+92
-30
No files matched your search
@@ -436,7 +436,8 @@ function collabSyncCards(PDO $db): array {
|
||||
FROM cards c
|
||||
INNER JOIN buckets b ON b.id = c.bucket_id AND b.collab_uid IS NOT NULL
|
||||
LEFT JOIN collab_card_state cs ON cs.card_id = c.id
|
||||
WHERE cs.last_push_at IS NULL OR c.updated_at > cs.last_push_at
|
||||
WHERE (cs.last_push_at IS NULL OR c.updated_at > cs.last_push_at)
|
||||
AND c.updated_at < datetime('now', '-2 seconds')
|
||||
")->fetchAll();
|
||||
|
||||
$assignUid = $db->prepare('UPDATE cards SET relay_uid = :u WHERE id = :id');
|
||||
|
||||
@@ -58,8 +58,15 @@ async function loadCollabMeta() {
|
||||
} catch (err) { /* silent; relay may be offline */ }
|
||||
}
|
||||
|
||||
let pollLocked = false;
|
||||
|
||||
async function pollOnce() {
|
||||
if (pollLocked) return;
|
||||
// Don't poll while user is actively editing — the push would race
|
||||
// with the in-progress save and corrupt card state.
|
||||
if (document.getElementById('modal')?.classList.contains('open')) return;
|
||||
try {
|
||||
pollLocked = true;
|
||||
const res = await hyprcrd.api('api/collab-buckets/poll', { method: 'POST' });
|
||||
if (!res?.ok) return;
|
||||
if (res.self) window._collabSelf = res.self;
|
||||
@@ -112,7 +119,7 @@ async function pollOnce() {
|
||||
const by = Array.isArray(res.card_stats?.blocked_by) ? res.card_stats.blocked_by : [];
|
||||
showBlockedToast(by);
|
||||
}
|
||||
} catch { /* silent */ }
|
||||
} catch { /* silent */ } finally { pollLocked = false; }
|
||||
}
|
||||
|
||||
function showConflictToast(n) {
|
||||
|
||||
@@ -14,8 +14,6 @@ describe('RRULE: Data Model', () => {
|
||||
const birthdays = state.cards.filter(c => (c.tags || '').includes('geburtstag'));
|
||||
for (const b of birthdays) {
|
||||
expect(b.tags).toContain('geburtstag');
|
||||
// Birthday titles start with date
|
||||
expect(b.title).toMatch(/^\d{4}-\d{2}-\d{2}/);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user