132 lines
4.9 KiB
JavaScript
132 lines
4.9 KiB
JavaScript
(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 continuation = [
|
|
['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 activeQueueNames = continuation.map(([name]) => name);
|
|
const allQueues = [
|
|
'today', 'tomorrow', 'week', 'agenda', 'delivery', 'gate', 'attention',
|
|
'update', 'following', 'filed', 'authored', 'later', 'draft', 'find', 'recaps',
|
|
];
|
|
|
|
function recommend() {
|
|
const counts = options.getCounts ? options.getCounts() : {};
|
|
const match = continuation.find(([name]) => Number(counts[name]) > 0);
|
|
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 active = activeQueueNames
|
|
.map(name => ({name, count: Math.max(0, Number(counts[name]) || 0)}))
|
|
.filter(item => item.count > 0);
|
|
activeQueueNames.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 };
|
|
});
|