feat: release mobile issue assignments (#183)
CI / lint (pull_request) Successful in 14s
CI / build-frontend (pull_request) Successful in 5s

This commit is contained in:
timmy committed 2026-08-07 09:24:21 +00:00
1 parent e96ff42dff
commit 87058d72e6
8 files changed
+264 -1

No files matched your search

+22
View File
@@ -353,6 +353,7 @@ textarea { resize: vertical; min-height: 120px; }
<div id="issue-comment-status" class="small" aria-live="assertive"></div>
</section>
<div class="issue-sheet-actions">
<button id="release-issue" type="button">Release assignment</button>
<button id="close-issue" type="button">Close issue</button>
<a id="open-issue-gitea" href="#" target="_blank" rel="noopener noreferrer">Open in Gitea</a>
</div>
@@ -1718,6 +1719,27 @@ textarea { resize: vertical; min-height: 120px; }
button.disabled = false;
}
});
qs('#release-issue').addEventListener('click', async () => {
if (!selectedIssue || !window.confirm('Release ' + selectedIssue.key + ' from your My Work?')) return;
const releasing = selectedIssue;
const button = qs('#release-issue');
button.disabled = true;
qs('#issue-sheet-status').textContent = 'Releasing assignment…';
try {
const confirmed = await issueController.release(selectedIssue, lastContextSnapshot?.user?.login);
lastContextSnapshot = buildMyWork.removeIssue(
lastContextSnapshot, releasing.repository, releasing.number
);
paintMyWork(lastContextSnapshot);
closeIssueSheet();
qs('#my-work-action-status').textContent = releasing.key + ' released.' +
(confirmed.available ? ' It is available in Find Work.' : ' Other assignees remain.');
} catch (error) {
qs('#issue-sheet-status').textContent = error.message + ' The issue remains in My Work; retry.';
button.disabled = false;
button.focus();
}
});
qs('#close-issue').addEventListener('click', async () => {
if (!selectedIssue || !window.confirm('Close ' + selectedIssue.key + '?')) return;
const closing = selectedIssue;
+18
View File
@@ -1,6 +1,7 @@
function createIssueSheet({ fetchJson, storage }) {
let commentRequest = null;
let closeRequest = null;
let releaseRequest = null;
let labelRequest = null;
const issuePath = item => 'api/v1/repos/' + item.repository.split('/').map(encodeURIComponent).join('/') +
'/issues/' + encodeURIComponent(item.number);
@@ -61,6 +62,23 @@ function createIssueSheet({ fetchJson, storage }) {
}).finally(() => { closeRequest = null; });
return closeRequest;
},
release(item, currentLogin) {
if (releaseRequest) return releaseRequest;
releaseRequest = fetchJson(issuePath(item) + '/release', {
method: 'PATCH',
headers: { Accept: 'application/json' },
}).then(result => {
if (
result?.number !== item.number ||
!Array.isArray(result.assignees) ||
result.assignees.includes(currentLogin)
) {
throw new Error('Issue release was not confirmed.');
}
return result;
}).finally(() => { releaseRequest = null; });
return releaseRequest;
},
comment(item, body) {
if (commentRequest) return commentRequest;
this.saveDraft(item, body);
+10
View File
@@ -335,6 +335,15 @@ function replaceIssueLabels(data, repository, number, labels) {
};
}
function removeIssue(data, repository, number) {
return {
...data,
issues: (data.issues || []).filter(item =>
item.repository !== repository || item.number !== number
),
};
}
function summarizeMyWork(items) {
const updates = items.filter((item) => item.has_update).length;
const reviews = items.filter((item) => item.is_review).length;
@@ -358,6 +367,7 @@ function countMyWork(items) {
if (typeof module !== 'undefined' && module.exports) {
buildMyWork.filterMyWork = filterMyWork;
buildMyWork.replaceIssueLabels = replaceIssueLabels;
buildMyWork.removeIssue = removeIssue;
buildMyWork.summarizeMyWork = summarizeMyWork;
buildMyWork.countMyWork = countMyWork;
buildMyWork.acknowledgeNotification = acknowledgeNotification;