The prefilled issue looked like a form to fear: raw headings in two languages, an HTML comment and a block of technical lines. Report a problem and Suggest something now open a window with one text box (a sentence or two, any language); Submit on GitHub opens the issue with that text, titled from its first words, in the browser's language, and the environment folded in <details> at the end when ticked (it can be looked at first). The issue forms ask just what went wrong, with optional screenshots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
3.2 KiB
JavaScript
81 lines
3.2 KiB
JavaScript
/**
|
|
* The feedback window: a problem or a suggestion is written here first, in the browser's
|
|
* own language and look, before GitHub opens with it filled in (feedback.js). One text
|
|
* box; the environment is attached only when ticked, and can be looked at first.
|
|
*/
|
|
|
|
import { translate } from './locales.js';
|
|
import { createViewScope } from './ui_lifecycle.js';
|
|
import { collectDiagnostics, openIssue } from './feedback.js';
|
|
|
|
const t = (key, params) => translate(key, params);
|
|
|
|
function el(tag, className, text) {
|
|
const node = document.createElement(tag);
|
|
if (className) node.className = className;
|
|
if (text !== undefined) node.textContent = text;
|
|
return node;
|
|
}
|
|
|
|
function button(className, label, onClick) {
|
|
const node = el('button', className, label);
|
|
node.type = 'button';
|
|
node.onclick = onClick;
|
|
return node;
|
|
}
|
|
|
|
/** `kind`: 'bug' | 'idea'. */
|
|
export function openFeedbackDialog(owner, kind = 'bug') {
|
|
const scope = createViewScope();
|
|
const isBug = kind === 'bug';
|
|
const overlay = el('div', 'anomalous-feedback-overlay');
|
|
const dialog = el('div', 'anomalous-feedback-dialog');
|
|
dialog.setAttribute('role', 'dialog');
|
|
dialog.setAttribute('aria-modal', 'true');
|
|
|
|
const text = el('textarea', 'anomalous-feedback-text');
|
|
text.rows = 5;
|
|
text.placeholder = t(isBug ? 'feedbackReportPlaceholder' : 'feedbackSuggestPlaceholder');
|
|
|
|
const attach = el('input');
|
|
attach.type = 'checkbox';
|
|
attach.checked = true;
|
|
const attachRow = el('label', 'anomalous-feedback-attach');
|
|
attachRow.append(attach, el('span', '', t('feedbackAttach')));
|
|
const preview = el('pre', 'anomalous-feedback-preview');
|
|
preview.hidden = true;
|
|
const showPreview = button('anomalous-feedback-link', t('feedbackShowAttach'), async () => {
|
|
preview.hidden = !preview.hidden;
|
|
if (!preview.hidden && !preview.textContent) preview.textContent = await collectDiagnostics(owner);
|
|
});
|
|
|
|
const close = () => scope.dispose();
|
|
const submit = button('anomalous-feedback-submit', t('feedbackSubmit'), async () => {
|
|
submit.disabled = true;
|
|
await openIssue(owner, kind, text.value, { environment: attach.checked });
|
|
close();
|
|
});
|
|
submit.disabled = true;
|
|
text.oninput = () => { submit.disabled = !text.value.trim(); };
|
|
|
|
const actions = el('div', 'anomalous-feedback-actions');
|
|
actions.append(button('anomalous-feedback-cancel', t('dialogCancel'), close), submit);
|
|
dialog.append(
|
|
el('h3', 'anomalous-feedback-title', t(isBug ? 'feedbackReport' : 'feedbackSuggest')),
|
|
el('p', 'anomalous-feedback-lead', t(isBug ? 'feedbackDialogLead' : 'feedbackDialogSuggestLead')),
|
|
text,
|
|
...(isBug ? [el('p', 'anomalous-feedback-hint', t('feedbackScreenshotHint'))] : []),
|
|
attachRow, showPreview, preview, actions,
|
|
);
|
|
overlay.append(dialog);
|
|
document.body.append(overlay);
|
|
scope.onDispose(() => overlay.remove());
|
|
scope.listen(overlay, 'mousedown', (event) => { if (event.target === overlay) close(); });
|
|
scope.listen(window, 'keydown', (event) => {
|
|
if (event.key !== 'Escape') return;
|
|
event.stopPropagation(); // the browser window behind stays open
|
|
close();
|
|
}, true);
|
|
text.focus();
|
|
}
|