171 lines
6.4 KiB
JavaScript
171 lines
6.4 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;
|
|
let evidenceItems = [];
|
|
const generatedUrls = new Set();
|
|
|
|
function releaseEvidenceUrls() {
|
|
generatedUrls.forEach(url => options.revokeObjectURL?.(url));
|
|
generatedUrls.clear();
|
|
evidenceItems = [];
|
|
}
|
|
|
|
function evidenceUrl(attachment) {
|
|
if (attachment?.blob) {
|
|
const url = options.createObjectURL(attachment.blob);
|
|
generatedUrls.add(url);
|
|
return url;
|
|
}
|
|
if (attachment?.data) {
|
|
return 'data:' + String(attachment.contentType || 'application/octet-stream') +
|
|
';base64,' + String(attachment.data);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function selectEvidence(index) {
|
|
const selected = evidenceItems[index];
|
|
if (!selected) return;
|
|
evidenceItems.forEach((item, position) =>
|
|
item.button.setAttribute('aria-pressed', position === index ? 'true' : 'false'));
|
|
const filename = selected.attachment.filename || 'Screenshot';
|
|
options.evidencePreview.hidden = false;
|
|
options.evidenceImage.src = selected.url;
|
|
options.evidenceImage.alt = 'Evidence ' + (index + 1) + ' of ' + evidenceItems.length + ': ' + filename;
|
|
options.evidencePosition.textContent = 'Evidence ' + (index + 1) + ' of ' + evidenceItems.length;
|
|
options.evidenceFilename.textContent = filename;
|
|
options.evidenceNote.textContent = selected.attachment.note || 'No evidence note.';
|
|
}
|
|
|
|
function renderVisualEvidence(attachments) {
|
|
releaseEvidenceUrls();
|
|
options.evidenceEmpty.hidden = attachments.length > 0;
|
|
options.evidencePreview.hidden = true;
|
|
options.evidenceImage.src = '';
|
|
evidenceItems = attachments.map((attachment, index) => {
|
|
const url = evidenceUrl(attachment);
|
|
const item = options.document.createElement('li');
|
|
const button = options.document.createElement('button');
|
|
const image = options.document.createElement('img');
|
|
const filename = attachment.filename || 'Screenshot';
|
|
button.setAttribute('type', 'button');
|
|
button.className = 'issue-filing-evidence-selector';
|
|
button.setAttribute('aria-label', 'Preview evidence ' + (index + 1) + ' of ' + attachments.length + ': ' + filename);
|
|
button.setAttribute('aria-pressed', 'false');
|
|
image.src = url;
|
|
image.alt = '';
|
|
button.appendChild(image);
|
|
item.appendChild(button);
|
|
return { attachment, button, item, url };
|
|
});
|
|
evidenceItems.forEach((entry, index) =>
|
|
entry.button.addEventListener('click', () => selectEvidence(index)));
|
|
options.evidenceList.replaceChildren(...evidenceItems.map(entry => entry.item));
|
|
if (evidenceItems.length) selectEvidence(0);
|
|
}
|
|
|
|
function close() {
|
|
options.sheet.hidden = true;
|
|
const previousTrigger = trigger;
|
|
trigger = null;
|
|
reviewed = null;
|
|
busy = false;
|
|
releaseEvidenceUrls();
|
|
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';
|
|
const owner = draft.assignee
|
|
? 'Owner: ' + (draft.assigneeName || draft.assignee) + ' (@' + draft.assignee + ')'
|
|
: 'Assigned to you';
|
|
options.metadata.textContent = [
|
|
labels.length ? 'Labels: ' + labels.join(', ') : 'No labels',
|
|
'Milestone: ' + milestone,
|
|
'Due: ' + dueDate,
|
|
owner,
|
|
].join(' · ');
|
|
if (options.blockerList) {
|
|
options.blockerList.replaceChildren(...(draft.blockers || []).map(blocker => {
|
|
const item = options.document.createElement('li');
|
|
item.textContent = blocker.repository + ' #' + blocker.number + ' — ' + blocker.title;
|
|
return item;
|
|
}));
|
|
}
|
|
const attachments = (draft.attachments || (draft.attachment ? [draft.attachment] : [])).filter(Boolean);
|
|
if (options.evidencePreview) {
|
|
renderVisualEvidence(attachments);
|
|
return;
|
|
}
|
|
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;
|
|
});
|