feat: publish draft pull requests from mobile (Closes #1344)
This commit is contained in:
1 parent
1a2297e943
commit
a4ae3e1c7f
6 files changed
+314
-2
No files matched your search
@@ -1763,6 +1763,8 @@
|
||||
<details class="pull-review-request" id="pull-review-request">
|
||||
<summary>Request review</summary>
|
||||
<div>
|
||||
<button id="publish-draft-pull" type="button" hidden>Ready for review</button>
|
||||
<div id="publish-draft-pull-status" class="small" aria-live="assertive"></div>
|
||||
<button id="load-pull-reviewers" type="button">Choose reviewer</button>
|
||||
<label for="pull-review-recipient" class="small">Eligible repository reviewer</label>
|
||||
<select id="pull-review-recipient" disabled><option value="">Select a teammate</option></select>
|
||||
|
||||
+47
-2
@@ -220,7 +220,7 @@ function resetReviewRequestControls(doc, detail) {
|
||||
qs('#pull-feedback-status').textContent = '';
|
||||
}
|
||||
|
||||
function bindReviewRequestControls(doc, controller, getSelected, getDetail) {
|
||||
function bindReviewRequestControls(doc, controller, getSelected, getDetail, getLogin) {
|
||||
const qs = selector => doc.querySelector(selector);
|
||||
const load = qs('#load-pull-reviewers');
|
||||
if (load.dataset.reviewRequestBound === 'true') return;
|
||||
@@ -228,6 +228,11 @@ function bindReviewRequestControls(doc, controller, getSelected, getDetail) {
|
||||
controller.setReviewDetail = detail => {
|
||||
resetReviewRequestControls(doc, detail);
|
||||
controller.edit?.setDetail(detail, Boolean(detail?.saved_at));
|
||||
const publishable = detail?.state === 'open' && detail?.draft === true &&
|
||||
detail?.author === getLogin?.() && detail?.head_sha;
|
||||
qs('#publish-draft-pull').hidden = !publishable;
|
||||
if (publishable) qs('#pull-review-request').open = true;
|
||||
qs('#publish-draft-pull-status').textContent = '';
|
||||
};
|
||||
resetReviewRequestControls(doc, null);
|
||||
qs('#request-updated-pull-review').addEventListener('click', () => {
|
||||
@@ -244,6 +249,30 @@ function bindReviewRequestControls(doc, controller, getSelected, getDetail) {
|
||||
qs('#pull-merge-state').textContent = 'Waiting for @' + result.reviewer + '’s review';
|
||||
qs('#merge-pull').disabled = true;
|
||||
};
|
||||
qs('#publish-draft-pull').addEventListener('click', async () => {
|
||||
const selected = getSelected?.();
|
||||
const detail = getDetail?.();
|
||||
if (!selected || !detail?.head_sha || detail.draft !== true ||
|
||||
!globalThis.confirm('Publish ' + selected.key + ' as ready for review?')) return;
|
||||
const button = qs('#publish-draft-pull');
|
||||
button.disabled = true;
|
||||
qs('#publish-draft-pull-status').textContent = 'Publishing draft…';
|
||||
try {
|
||||
const result = await controller.publishReady(selected, detail.head_sha);
|
||||
if (getSelected?.() !== selected || getDetail?.() !== detail) return;
|
||||
Object.assign(detail, result);
|
||||
selected.title = result.title;
|
||||
qs('#pull-sheet-title').textContent = result.title;
|
||||
controller.setReviewDetail(detail);
|
||||
qs('#publish-draft-pull-status').textContent = 'Published and ready for review.';
|
||||
qs('#pull-review-request').open = true;
|
||||
load.focus();
|
||||
} catch (error) {
|
||||
qs('#publish-draft-pull-status').textContent = error.message + ' The pull request remains a draft; retry.';
|
||||
button.disabled = false;
|
||||
button.focus();
|
||||
}
|
||||
});
|
||||
qs('#pull-reviewer-statuses').addEventListener('click', async event => {
|
||||
const button = event.target.closest?.('[data-cancel-review-request]');
|
||||
if (!button || button.disabled) return;
|
||||
@@ -534,7 +563,7 @@ function bindContextEditor(doc, controller, getSelected, getDetail, getLogin) {
|
||||
}
|
||||
|
||||
function bindOwnershipControls(doc, controller, getSelected, finish, getDetail, getLogin) {
|
||||
bindReviewRequestControls(doc, controller, getSelected, getDetail);
|
||||
bindReviewRequestControls(doc, controller, getSelected, getDetail, getLogin);
|
||||
bindFeedbackControls(doc, controller, getSelected, getDetail, getLogin);
|
||||
controller.edit = bindContextEditor(doc, controller, getSelected, getDetail, getLogin);
|
||||
const qs = selector => doc.querySelector(selector);
|
||||
@@ -610,6 +639,7 @@ function createPullSheet({ fetchJson, storage, createConversationPager = globalT
|
||||
let reviewCandidateRequest = null;
|
||||
let reviewRequestMutation = null;
|
||||
let reviewCancelMutation = null;
|
||||
let readyMutation = null;
|
||||
let editRequest = null;
|
||||
let feedbackRequest = null;
|
||||
const reviewRequests = new Map();
|
||||
@@ -719,6 +749,21 @@ function createPullSheet({ fetchJson, storage, createConversationPager = globalT
|
||||
}).finally(() => { reviewCancelMutation = null; });
|
||||
return reviewCancelMutation;
|
||||
},
|
||||
publishReady(item, expectedHeadSha) {
|
||||
if (readyMutation) return readyMutation;
|
||||
readyMutation = fetchJson(pathFor(item) + '/ready', {
|
||||
method:'PATCH',
|
||||
headers:{ Accept:'application/json', 'Content-Type':'application/json' },
|
||||
body:JSON.stringify({ expected_head_sha:expectedHeadSha }),
|
||||
}).then(result => {
|
||||
if (result?.number !== item.number || result?.head_sha !== expectedHeadSha ||
|
||||
result?.state !== 'open' || result?.draft !== false || !result?.title) {
|
||||
throw new Error('Draft publication was not confirmed.');
|
||||
}
|
||||
return result;
|
||||
}).finally(() => { readyMutation = null; });
|
||||
return readyMutation;
|
||||
},
|
||||
loadEditDraft(item) {
|
||||
try {
|
||||
const value = JSON.parse(storage?.getItem(editDraftKey(item)) || 'null');
|
||||
|
||||
Reference in new issue
Block a user