sync-event toasts, image pull ordering, stale banner field diff

- replace chat-bot sync notifications with a dedicated relay_sync_events
  queue: POST/GET /api/sync-events, drained by /api/relay/poll and
  surfaced as stacking toasts via caldav.js. Old /api/chat/bot removed,
  bot=1 rows purged on bootstrap, orange bot rendering dropped from
  relay UI. Chat thread stays clean.
- collab pull: fetch attachments BEFORE applying the body so the moment
  state.cards reflects the new reference the file is on disk. Fixes the
  "preview shows broken/missing image, editor shows it" race where the
  browser cached the 404 between attachment landing and user re-render.
- detail stale banner now compares title/body/color/tags in addition to
  updated_at — robust against second-granularity timestamp collisions
  and any other case where updated_at doesn't tick but content differs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.6 committed 2026-04-14 23:00:30 +02:00
1 parent 26f95ba079
commit 1966f8f4c0
10 files changed
+170 -75

No files matched your search

+3 -11
View File
@@ -719,20 +719,12 @@ async function loadChatHistory(peer, quiet = false) {
return;
}
container.innerHTML = messages.map(m => {
if (m.bot) {
return `
<div class="chat-msg bot">
<div><i class="ph ph-robot"></i> ${escapeHtml(m.body)}</div>
<div class="msg-time">${formatChatTime(m.created_at)}</div>
</div>`;
}
return `
container.innerHTML = messages.map(m => `
<div class="chat-msg ${m.mine ? 'mine' : 'theirs'}">
<div>${escapeHtml(m.body)}</div>
<div class="msg-time">${formatChatTime(m.created_at)}${m.mine && m.seen ? ' <i class="ph ph-checks"></i>' : ''}</div>
</div>`;
}).join('');
</div>
`).join('');
if (wasAtBottom || !quiet) {
container.scrollTop = container.scrollHeight;
-7
View File
@@ -280,13 +280,6 @@ label.checkbox input[type="checkbox"] { accent-color:var(--accent); cursor:point
}
.chat-msg.mine { align-self: flex-end; background: var(--accent); color: var(--bg); border-bottom-right-radius: 2px; }
.chat-msg.theirs { align-self: flex-start; background: var(--raised); color: var(--text); border: 1px solid var(--border); border-bottom-left-radius: 2px; }
.chat-msg.bot {
align-self: center; max-width: 90%;
background: rgba(251, 146, 60, 0.12); color: #fb923c;
border: 1px solid rgba(251, 146, 60, 0.35);
font-size: 11px; text-align: center;
}
.chat-msg.bot .msg-time { text-align: center; }
.chat-msg .msg-time { font-family: var(--pixel); font-size: 8px; opacity: 0.6; margin-top: 4px; }
.chat-msg.mine .msg-time { text-align: right; }
.chat-input-bar { display: flex; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--border); }