personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

support: split announcements first-paint and stale errors

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+38 -11
+38 -11
apps/support/workspace.html
··· 315 315 } 316 316 .support-announcements h4 { margin: 0 0 0.25rem 0; font-size: 0.9rem; } 317 317 .support-announcements p { margin: 0; font-size: 0.85rem; } 318 + .support-announcements-error { color: #92400e; } 319 + .support-announcements-stale { 320 + margin: -1rem 0 1.5rem; 321 + font-size: 0.8rem; 322 + color: #92400e; 323 + } 318 324 319 325 /* Diagnostics */ 320 326 .support-diagnostics-desc { ··· 561 567 <script> 562 568 (function() { 563 569 let ticketCount = 0; 570 + let announcementsFirstPaintDone = false; 571 + let announcementsLastSuccessAt = null; 564 572 565 573 // Tab navigation 566 574 function activateTab(sectionName) { ··· 996 1004 }); 997 1005 998 1006 // Load announcements 1007 + function clearAnnouncementsStale() { 1008 + const stale = document.getElementById('support-announcements-stale'); 1009 + if (stale) stale.remove(); 1010 + } 1011 + 999 1012 async function loadAnnouncements() { 1000 1013 const banner = document.getElementById('support-announcements-banner'); 1001 1014 try { 1002 - const resp = await fetch('/app/support/api/announcements'); 1003 - if (!resp.ok) return; 1004 - const items = await resp.json(); 1005 - if (!items.length) return; 1015 + const items = await window.apiJson('/app/support/api/announcements'); 1016 + announcementsFirstPaintDone = true; 1017 + announcementsLastSuccessAt = new Date(); 1018 + clearAnnouncementsStale(); 1019 + if (!items.length) { 1020 + banner.style.display = 'none'; 1021 + banner.innerHTML = ''; 1022 + return; 1023 + } 1006 1024 banner.style.display = ''; 1007 1025 const icons = {'known-issue': '⚠️', 'maintenance': '🔧', 'info': '📢'}; 1008 1026 banner.innerHTML = items.map(a => 1009 1027 `<div><h4>${icons[a.type] || '📢'} ${esc(a.title || '')}</h4><p style="margin:0;">${esc((a.content || '').slice(0, 200))}</p></div>` 1010 1028 ).join(''); 1011 - } catch (e) { 1012 - console.warn('Failed to load announcements:', e); 1013 - banner.style.display = ''; 1014 - banner.style.background = 'none'; 1015 - banner.style.border = 'none'; 1016 - banner.style.padding = '0.5rem 0'; 1017 - banner.innerHTML = '<p style="margin:0;font-size:0.8rem;color:#666;">couldn\'t load announcements</p>'; 1029 + } catch (err) { 1030 + if (!announcementsFirstPaintDone) { 1031 + banner.style.display = ''; 1032 + banner.innerHTML = '<p class="support-announcements-error">' + 1033 + esc(err.serverMessage || "Couldn't load announcements. Reload to try again.") + 1034 + '</p>'; 1035 + } else { 1036 + clearAnnouncementsStale(); 1037 + const stale = document.createElement('div'); 1038 + stale.id = 'support-announcements-stale'; 1039 + stale.className = 'support-announcements-stale'; 1040 + stale.textContent = 'Couldn\'t refresh announcements - showing last known state.' + 1041 + (announcementsLastSuccessAt ? ' Last updated ' + announcementsLastSuccessAt.toLocaleString() + '.' : ''); 1042 + banner.insertAdjacentElement('afterend', stale); 1043 + } 1044 + window.logError(err, { context: 'support-announcements' }); 1018 1045 } 1019 1046 } 1020 1047