(status)
| 17207 | // Silently fail for background checks |
| 17208 | console.debug('Background update check failed:', error); |
| 17209 | } |
| 17210 | } |
| 17211 | |
| 17212 | // ── Files nav flag ─────────────────────────────────────────────────────────── |
| 17213 | // Put a dot on the "Files" nav word (like the Config update flag) when a file is |
| 17214 | // sent to this unit (its mesh Inbox has items) OR shared to the mesh by a peer |
| 17215 | // since it was last viewed. |
| 17216 | let _filesFlagInbox = 0; |
| 17217 | let _filesFlagSharedNew = false; |
| 17218 | function _applyFilesFlag() { |
| 17219 | const on = _filesFlagInbox > 0 || _filesFlagSharedNew; |
| 17220 | document.querySelectorAll('[data-tab="files"]').forEach(btn => { |
| 17221 | let dot = btn.querySelector('.files-flag'); |
| 17222 | if (on) { |
| 17223 | if (!dot) { |
| 17224 | dot = document.createElement('span'); |
| 17225 | dot.className = 'files-flag absolute -top-1 -right-1 w-3 h-3 bg-amber-500 rounded-full pulse-glow'; |
| 17226 | btn.style.position = 'relative'; |
| 17227 | btn.appendChild(dot); |
| 17228 | } |
| 17229 | } else if (dot) { |
| 17230 | dot.remove(); |
| 17231 | } |
| 17232 | }); |
| 17233 | } |
| 17234 | // Sent-to-this-unit case (Inbox count). |
| 17235 | function setFilesNavFlag(count) { _filesFlagInbox = count; _applyFilesFlag(); } |
| 17236 | function refreshFilesFlag() { |
| 17237 | networkAwareFetch('/api/mesh/inbox') |
| 17238 | .then(r => r.json()) |
| 17239 | .then(d => setFilesNavFlag((d && d.items) ? d.items.length : 0)) |
| 17240 | .catch(() => { /* silent — background check */ }); |
| 17241 | } |
| 17242 | // Shared-to-the-mesh case: flag when a peer has shared more files than we last |
| 17243 | // saw. Baselines silently on first observation so pre-existing shares don't flag. |
| 17244 | function refreshSharedFlag() { |
| 17245 | networkAwareFetch('/api/mesh/share') |
| 17246 | .then(r => r.json()) |
| 17247 | .then(d => { |
| 17248 | const peerCount = ((d && d.items) || []).filter(i => !i.is_local).length; |
| 17249 | let raw = null; |
| 17250 | try { raw = localStorage.getItem('mesh_share_seen'); } catch (e) { /* ignore */ } |
| 17251 | if (raw === null) { |
| 17252 | try { localStorage.setItem('mesh_share_seen', String(peerCount)); } catch (e) { /* ignore */ } |
| 17253 | _filesFlagSharedNew = false; |
| 17254 | } else { |
| 17255 | _filesFlagSharedNew = peerCount > (parseInt(raw, 10) || 0); |
| 17256 | } |
| 17257 | _applyFilesFlag(); |
| 17258 | }) |
| 17259 | .catch(() => { /* silent — background check */ }); |
| 17260 | } |
| 17261 | // Everything currently shared is now "seen" (called when Mesh Share is opened). |
| 17262 | function markSharedSeen(peerCount) { |
| 17263 | try { localStorage.setItem('mesh_share_seen', String(peerCount || 0)); } catch (e) { /* ignore */ } |
| 17264 | _filesFlagSharedNew = false; |
| 17265 | _applyFilesFlag(); |
| 17266 | } |
no test coverage detected