feat: triage mobile issue capture with labels (#163)
This commit is contained in:
1 parent
e5f001f2b0
commit
b6390d3298
6 files changed
+297
-19
No files matched your search
+46
-1
@@ -138,6 +138,10 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
.create-issue-form { display:grid; gap:12px; }
|
||||
.create-issue-form label { display:grid; gap:6px; }
|
||||
.create-issue-form select { min-height:44px; padding:8px; border-radius:8px; border:1px solid #1f3a5f; background:#0b1526; color:#e5e7eb; }
|
||||
.create-issue-labels { display:grid; gap:8px; margin:0; padding:0; border:0; }
|
||||
.create-issue-label-list { display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); gap:8px; }
|
||||
.create-issue-label-option { min-height:44px; display:flex !important; grid-template-columns:auto 1fr !important; align-items:center; gap:8px; padding:8px 10px; border:1px solid #2a496e; border-radius:10px; background:#10213a; }
|
||||
.create-issue-label-option input { width:20px; height:20px; margin:0; }
|
||||
.create-issue-actions { position:sticky; bottom:0; display:grid; gap:8px; padding:10px 0; padding-bottom:calc(10px + env(safe-area-inset-bottom)); background:#0b1526; }
|
||||
.pull-sheet { position:fixed; inset:0; z-index:58; display:none; justify-content:flex-end; background:rgba(5,12,21,.72); backdrop-filter:blur(4px); }
|
||||
.pull-sheet.open { display:flex; }
|
||||
@@ -332,6 +336,11 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
<label for="create-issue-body">Description <span class="small">Optional</span>
|
||||
<textarea id="create-issue-body" maxlength="10000"></textarea>
|
||||
</label>
|
||||
<fieldset class="create-issue-labels" id="create-issue-labels" aria-describedby="create-issue-label-status">
|
||||
<legend>Labels <span class="small">Optional</span></legend>
|
||||
<div class="small" id="create-issue-label-status" aria-live="polite">Choose a repository to load labels.</div>
|
||||
<div class="create-issue-label-list" id="create-issue-label-list"></div>
|
||||
</fieldset>
|
||||
<div class="small">The issue will be assigned to you.</div>
|
||||
<div class="create-issue-actions">
|
||||
<button id="submit-new-issue" type="submit">Create & assign to me</button>
|
||||
@@ -948,14 +957,43 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
if (pullTrigger?.isConnected) pullTrigger.focus();
|
||||
}
|
||||
|
||||
function selectedIssueLabelIds() {
|
||||
return Array.from(document.querySelectorAll('input[name="create-issue-label"]:checked'))
|
||||
.map(input => Number(input.value)).filter(Number.isInteger);
|
||||
}
|
||||
|
||||
function saveIssueCaptureDraft() {
|
||||
issueCapture.saveDraft({
|
||||
repository: qs('#create-issue-repository').value,
|
||||
title: qs('#create-issue-title').value,
|
||||
body: qs('#create-issue-body').value,
|
||||
labelIds: selectedIssueLabelIds(),
|
||||
});
|
||||
}
|
||||
|
||||
async function loadIssueLabels(repository, selectedIds = []) {
|
||||
const list = qs('#create-issue-label-list');
|
||||
const status = qs('#create-issue-label-status');
|
||||
list.innerHTML = '';
|
||||
if (!repository) {
|
||||
status.textContent = 'Choose a repository to load labels.';
|
||||
return;
|
||||
}
|
||||
status.textContent = 'Loading labels…';
|
||||
try {
|
||||
const labels = await issueCapture.loadLabels(repository);
|
||||
const selected = new Set(selectedIds.map(Number));
|
||||
list.innerHTML = labels.map(label =>
|
||||
'<label class="create-issue-label-option"><input type="checkbox" name="create-issue-label" value="' +
|
||||
Number(label.id) + '"' + (selected.has(Number(label.id)) ? ' checked' : '') + '><span>' +
|
||||
escapeHtml(label.name) + '</span></label>'
|
||||
).join('');
|
||||
status.textContent = labels.length ? 'Select labels to triage this issue.' : 'This repository has no labels.';
|
||||
} catch (error) {
|
||||
status.textContent = 'Labels could not be loaded. You can still create the issue without labels.';
|
||||
}
|
||||
}
|
||||
|
||||
function openCreateIssueSheet() {
|
||||
const captureDraft = issueCapture.loadDraft();
|
||||
const repositories = lastContextSnapshot?.repos || [];
|
||||
@@ -967,6 +1005,7 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
}
|
||||
qs('#create-issue-title').value = captureDraft.title;
|
||||
qs('#create-issue-body').value = captureDraft.body;
|
||||
loadIssueLabels(qs('#create-issue-repository').value, captureDraft.labelIds);
|
||||
qs('#create-issue-status').textContent = repositories.length ? '' : 'No accessible repositories are available.';
|
||||
qs('#submit-new-issue').disabled = !repositories.length;
|
||||
qs('#create-issue-sheet').classList.add('open');
|
||||
@@ -1256,15 +1295,21 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
saveIssueCaptureDraft();
|
||||
closeCreateIssueSheet();
|
||||
});
|
||||
['#create-issue-repository', '#create-issue-title', '#create-issue-body'].forEach(selector =>
|
||||
['#create-issue-title', '#create-issue-body'].forEach(selector =>
|
||||
qs(selector).addEventListener('input', saveIssueCaptureDraft)
|
||||
);
|
||||
qs('#create-issue-repository').addEventListener('change', event => {
|
||||
loadIssueLabels(event.target.value);
|
||||
saveIssueCaptureDraft();
|
||||
});
|
||||
qs('#create-issue-label-list').addEventListener('change', saveIssueCaptureDraft);
|
||||
qs('#create-issue-form').addEventListener('submit', async event => {
|
||||
event.preventDefault();
|
||||
const captureDraft = {
|
||||
repository: qs('#create-issue-repository').value,
|
||||
title: qs('#create-issue-title').value.trim(),
|
||||
body: qs('#create-issue-body').value.trim(),
|
||||
labelIds: selectedIssueLabelIds(),
|
||||
};
|
||||
if (!captureDraft.repository || !captureDraft.title) {
|
||||
qs('#create-issue-status').textContent = 'Choose a repository and add a title.';
|
||||
|
||||
Reference in new issue
Block a user