78 lines
2.5 KiB
JavaScript
78 lines
2.5 KiB
JavaScript
function createFindWork({ fetchJson, onItems, onPagination, onStatus }) {
|
|
let available = [];
|
|
let pagination = { page: 1, total: 0, has_more: false };
|
|
let loadRequest = null;
|
|
let claimRequest = null;
|
|
|
|
function apply(result, append) {
|
|
const incoming = Array.isArray(result?.items) ? result.items : [];
|
|
if (append) {
|
|
const byId = new Map(available.map(item => [item.id, item]));
|
|
incoming.forEach(item => {
|
|
if (item && !byId.has(item.id)) byId.set(item.id, { ...item });
|
|
});
|
|
available = Array.from(byId.values());
|
|
} else {
|
|
available = incoming.map(item => ({ ...item }));
|
|
}
|
|
pagination = {
|
|
page: Number(result?.page) || 1,
|
|
total: Number(result?.total) || available.length,
|
|
has_more: result?.has_more === true,
|
|
};
|
|
onItems(available.slice());
|
|
onPagination({ ...pagination });
|
|
}
|
|
|
|
function loadPage(page, append) {
|
|
if (loadRequest) return loadRequest;
|
|
loadRequest = fetchJson('api/v1/available-issues?page=' + page, {
|
|
headers: { Accept: 'application/json' },
|
|
}).then(result => {
|
|
apply(result, append);
|
|
return result;
|
|
}).finally(() => { loadRequest = null; });
|
|
return loadRequest;
|
|
}
|
|
|
|
return {
|
|
reset(result) {
|
|
apply(result, false);
|
|
},
|
|
load() {
|
|
return loadPage(1, false);
|
|
},
|
|
loadMore() {
|
|
if (!pagination.has_more) return Promise.resolve(false);
|
|
return loadPage(pagination.page + 1, true);
|
|
},
|
|
items() {
|
|
return available.slice();
|
|
},
|
|
claim(item) {
|
|
if (claimRequest) return claimRequest;
|
|
const key = item.repository + '#' + item.number;
|
|
onStatus('Assigning ' + key + '…');
|
|
const path = 'api/v1/repos/' + item.repository.split('/').map(encodeURIComponent).join('/') +
|
|
'/issues/' + encodeURIComponent(item.number) + '/claim';
|
|
claimRequest = fetchJson(path, {
|
|
method: 'PATCH',
|
|
headers: { Accept: 'application/json' },
|
|
}).then(confirmed => {
|
|
if (!Array.isArray(confirmed?.assignees) || !confirmed.assignees.length) {
|
|
throw new Error('Issue assignment was not confirmed.');
|
|
}
|
|
available = available.filter(candidate =>
|
|
candidate.repository !== item.repository || candidate.number !== item.number
|
|
);
|
|
onItems(available.slice());
|
|
onStatus('Assigned ' + key + ' to you.');
|
|
return confirmed;
|
|
}).finally(() => { claimRequest = null; });
|
|
return claimRequest;
|
|
},
|
|
};
|
|
}
|
|
|
|
if (typeof module !== 'undefined' && module.exports) module.exports = createFindWork;
|