stackchain-dashboard/frontend/issue-filing-review.js
timmy 59a2e4f616
All checks were successful
CI / lint (pull_request) Successful in 1m42s
CI / build-release (pull_request) Successful in 5s
CI / release-candidate (pull_request) Has been skipped
feat: review mobile issue payload before filing (Closes #833)
2026-08-14 15:36:54 +00:00

94 lines
3.2 KiB
JavaScript

(function(root, factory) {
const api = factory();
if (typeof module === 'object' && module.exports) module.exports = api;
else root.createIssueFilingReview = api;
})(typeof self !== 'undefined' ? self : this, function() {
'use strict';
const INTENT_LABELS = {
'create-and-assign': 'Create & assign to me',
'create-and-start': 'Create & start',
'follow-up-and-next': 'Create follow-up & next',
};
function clone(value) {
if (typeof structuredClone === 'function') return structuredClone(value);
return JSON.parse(JSON.stringify(value));
}
function create(options) {
let reviewed = null;
let trigger = null;
let busy = false;
function close() {
options.sheet.hidden = true;
const previousTrigger = trigger;
trigger = null;
reviewed = null;
busy = false;
options.confirmButton.disabled = false;
previousTrigger?.focus();
}
function render(payload) {
const draft = payload.draft;
options.repository.textContent = draft.repository || 'No repository';
options.intent.textContent = INTENT_LABELS[payload.intent] || payload.intent;
options.title.textContent = draft.title;
options.body.textContent = draft.body || 'No note provided.';
const labels = (draft.labels || []).map(label => typeof label === 'string' ? label : label.name);
const milestone = draft.milestone?.title || draft.milestoneTitle || 'No milestone';
const dueDate = draft.dueDate || draft.due_date || 'No due date';
options.metadata.textContent = [
labels.length ? 'Labels: ' + labels.join(', ') : 'No labels',
'Milestone: ' + milestone,
'Due: ' + dueDate,
'Assigned to you',
].join(' · ');
const attachments = (draft.attachments || (draft.attachment ? [draft.attachment] : [])).filter(Boolean);
options.evidenceList.replaceChildren(...attachments.map((attachment, index) => {
const item = options.document.createElement('li');
item.textContent = (index + 1) + '. ' + (attachment.filename || 'Screenshot') +
(attachment.note ? ' — ' + attachment.note : '');
return item;
}));
}
function open(payload, opener) {
reviewed = clone(payload);
trigger = opener || null;
busy = false;
options.confirmButton.disabled = false;
render(reviewed);
options.sheet.hidden = false;
options.backButton.focus();
}
options.backButton.addEventListener('click', close);
options.confirmButton.addEventListener('click', async () => {
if (!reviewed || busy) return;
busy = true;
options.confirmButton.disabled = true;
try {
await options.onConfirm(reviewed);
close();
} catch (error) {
busy = false;
options.confirmButton.disabled = false;
if (options.status) options.status.textContent = error.message;
options.confirmButton.focus();
}
});
options.document.addEventListener('keydown', event => {
if (!options.sheet.hidden && event.key === 'Escape' && !busy) {
event.preventDefault();
close();
}
});
return { close, open };
}
return create;
});