(function (root, factory) { if (typeof module === 'object' && module.exports) module.exports = factory; else root.createMobileQueueLauncher = factory; })(typeof self !== 'undefined' ? self : this, function createMobileQueueLauncher(options) { const emptyMessages = { attention: 'No items need attention.', update: 'No unread updates are ready to open.', later: 'No deferred work is ready to open.', draft: 'No drafts are ready to open.', }; const labels = { delivery: 'Recover Delivery', gate: 'Review Human Gates', attention: 'Start Attention', today: 'Continue Today', update: 'Resume Updates', agenda: 'Open Agenda', following: 'Review Following', authored: 'Open My PRs', filed: 'Review Filed', later: 'Start Later', draft: 'Open Drafts', }; const criticalQueueNames = ['delivery', 'gate']; const defaultRoutineOrder = [ 'attention', 'today', 'update', 'agenda', 'following', 'authored', 'filed', 'later', 'draft', ]; const onlineOnlyQueues = new Set(['delivery', 'gate']); const allQueues = [ 'today', 'tomorrow', 'week', 'agenda', 'delivery', 'gate', 'attention', 'update', 'following', 'filed', 'authored', 'later', 'draft', 'find', 'recaps', ]; function routineOrder() { const proposed = options.getRoutineOrder ? options.getRoutineOrder() : defaultRoutineOrder; if (!Array.isArray(proposed) || proposed.length !== defaultRoutineOrder.length || new Set(proposed).size !== defaultRoutineOrder.length || proposed.some(name => !defaultRoutineOrder.includes(name))) return defaultRoutineOrder.slice(); return proposed.slice(); } function activeQueueNames() { return criticalQueueNames.concat(routineOrder()); } function recommend() { const counts = options.getCounts ? options.getCounts() : {}; const online = options.isOnline ? options.isOnline() : true; const match = activeQueueNames().map(name => [name, labels[name]]).find(([name]) => Number(counts[name]) > 0 && (online || !onlineOnlyQueues.has(name)) ); if (!match) return {name: 'find', count: 0, label: 'Find Work'}; const [name, label] = match; const count = Math.max(0, Number(counts[name]) || 0); return {name, count, label: label + ' (' + count + ')'}; } function adaptiveRecommendation() { const preparation = options.getPreparation ? options.getPreparation() : null; if (preparation && (preparation.active || Number(preparation.total) > 0)) { const prefix = preparation.active ? 'Resume preparation · ' : 'Start day · '; return {name: 'prepare', count: Math.max(0, Number(preparation.total) || 0), label: prefix + preparation.label}; } return recommend(); } function presentation() { const counts = options.getCounts ? options.getCounts() : {}; const names = activeQueueNames(); const active = names .map(name => ({name, count: Math.max(0, Number(counts[name]) || 0)})) .filter(item => item.count > 0); names.forEach(name => { if (counts[name + 'Unavailable'] && !active.some(item => item.name === name)) { active.push({name, unavailable: true}); } }); return { nextUp: adaptiveRecommendation(), active, planning: ['today', 'tomorrow', 'week'], all: allQueues.slice(), }; } function renderPresentation() { const view = presentation(); const planning = new Set(view.planning); const active = view.active.filter(item => !planning.has(item.name)); const activeNames = new Set(active.map(item => item.name)); if (options.nextAction) { options.nextAction.textContent = view.nextUp.label; options.nextAction.dataset.queue = view.nextUp.name; const prefix = view.nextUp.name === 'prepare' ? 'Start or continue: ' : 'Next up: '; options.nextAction.setAttribute('aria-label', prefix + view.nextUp.label); } active.forEach(item => { const row = options.rows?.[item.name]; if (!row) return; if (item.unavailable) row.setAttribute('data-unavailable', 'true'); else row.removeAttribute('data-unavailable'); options.activeList?.append(row); }); view.planning.forEach(name => { const row = options.rows?.[name]; if (row) options.planningList?.append(row); }); view.all.forEach(name => { if (planning.has(name) || activeNames.has(name)) return; const row = options.rows?.[name]; if (!row) return; row.removeAttribute('data-unavailable'); options.allList?.append(row); }); if (options.activeSection) options.activeSection.hidden = active.length === 0; return view; } function open(name) { if (name === 'delivery' && options.openDelivery) return options.openDelivery(); if (name === 'gate' && options.openHumanGates) return options.openHumanGates(); if (name === 'today') return options.openToday(); if (name === 'agenda') return options.openAgenda(); if (name === 'update' && options.openUpdates) return options.openUpdates(); if (name === 'following' && options.openFollowing) return options.openFollowing(); if (name === 'filed' && options.openFiled) return options.openFiled(); options.selectFilter(name); const action = options.firstAction(name); if (!action) { options.announce(emptyMessages[name] || 'No work is ready to open.'); return 'empty'; } action.click(); return 'opened'; } function continueWork() { const next = adaptiveRecommendation(); if (next.name === 'prepare') { options.openPreparation(); return 'prepare'; } if (next.name === 'find') { options.openFindWork(); return 'find'; } return open(next.name); } return { open, recommend, adaptiveRecommendation, presentation, renderPresentation, continueWork }; });