function createProgressiveMyWork({ document, fetchSnapshot }) { const list = document.querySelector('#my-work-list'); const status = document.querySelector('#my-work-status'); const filters = Array.from(document.querySelectorAll('[data-work-filter]')); const listeners = []; let items = []; let active = 'all'; let stopped = false; const escapeHtml = value => String(value || '').replace(/[&<>"']/g, character => ({ '&':'&', '<':'<', '>':'>', '"':'"', "'":''', })[character]); const safeUrl = value => { try { const url = new URL(String(value || ''), globalThis.location?.href || 'https://invalid.example/'); return ['http:', 'https:'].includes(url.protocol) ? url.href : ''; } catch (_error) { return ''; } }; const visibleItems = () => active === 'all' ? items : items.filter(item => active === 'review' ? item.is_review : active === 'update' ? item.has_update : active === 'attention' ? item.needs_attention : item.kind === active ); const render = () => { if (stopped || !list) return; const visible = visibleItems(); list.innerHTML = visible.length ? visible.map(item => { const href = safeUrl(item.url); const title = escapeHtml(item.title || item.key || 'Untitled work'); const context = escapeHtml(item.key || ''); const reason = escapeHtml(item.reason || 'Assigned to you'); return '
' + (href ? '' : '
') + '' + title + '' + context + ' · ' + reason + '' + (href ? '' : '
') + '
'; }).join('') : '
No work in this queue.
'; filters.forEach(button => button.setAttribute('aria-pressed', String(button.dataset.workFilter === active))); }; filters.forEach(button => { const listener = () => { active = button.dataset.workFilter || 'all'; render(); }; button.addEventListener('click', listener); listeners.push([button, listener]); }); return { async start() { if (status) status.textContent = 'Loading assigned work…'; try { const snapshot = await fetchSnapshot(); if (stopped) return false; const context = snapshot?.context || snapshot || {}; items = buildMyWork({ ...context, notifications:snapshot?.notifications || context.notifications || [] }); render(); const assigned = items.filter(item => item.is_assigned).length; if (status) status.textContent = assigned + ' assigned work item' + (assigned === 1 ? '' : 's') + ' ready.'; return true; } catch (_error) { if (status && !stopped) status.textContent = 'Assigned work is reconnecting…'; return false; } }, stop() { stopped = true; listeners.forEach(([button, listener]) => button.removeEventListener?.('click', listener)); }, }; } if (typeof window !== 'undefined' && typeof document !== 'undefined') { window.stackchainProgressiveMyWork = createProgressiveMyWork({ document, fetchSnapshot: async () => { const response = await fetch('api/v1/live', { headers:{Accept:'application/json'} }); if (!response.ok) throw new Error('HTTP ' + response.status); return response.json(); }, }); void window.stackchainProgressiveMyWork.start(); } if (typeof module !== 'undefined' && module.exports) module.exports = createProgressiveMyWork;