Add issue label selection
Build / build (push) Successful in 12s

This commit is contained in:
2026-07-18 13:01:36 -05:00
parent cb33bc0aa1
commit 04ee2c05a9
9 changed files with 168 additions and 104 deletions
+47 -25
View File
@@ -4,9 +4,11 @@ import {
appStore,
CHROME_PROFILE_NAME,
findKnownUrlForBase,
ISSUE_LABEL_OPTIONS,
type AgentProfile,
type AddUrlMode,
type AppView,
type IssueLabelOption,
type OpenIssue,
type OpenIssuesStateFilter,
type ScreenshotAttachment
@@ -389,6 +391,24 @@ function renderAgentOptions(agents: AgentProfile[], selectedAgentId: string): st
.join("");
}
function renderLabelOptions(selectedLabels: IssueLabelOption[], target: "draft" | "edit"): string {
return `
<fieldset class="label-fieldset">
<legend>Labels</legend>
<div class="label-option-grid">
${ISSUE_LABEL_OPTIONS.map(
(label) => `
<label class="checkbox-row label-option">
<input type="checkbox" value="${escapeHtml(label)}" data-label-target="${target}" ${selectedLabels.includes(label) ? "checked" : ""} />
<span>${escapeHtml(label)}</span>
</label>
`
).join("")}
</div>
</fieldset>
`;
}
function renderBodyText(body: string, emptyText: string): string {
const trimmed = body.trim();
if (!trimmed) {
@@ -540,7 +560,6 @@ function renderIssueRows(issues: OpenIssue[], selectedIssueNumber: number | null
<span class="issue-state">${escapeHtml(issue.state)}</span>
<span class="issue-meta">${formatDate(issue.createdAt)}</span>
</button>
<button class="secondary-button compact-button" type="button" data-ready-issue="${issue.number}" data-issue-repo="${escapeHtml(issue.repoFullName)}" ${state.isUpdatingIssue ? "disabled" : ""}>Ready</button>
<button class="danger-button compact-button" type="button" data-delete-issue="${issue.number}" data-issue-repo="${escapeHtml(issue.repoFullName)}" ${state.isUpdatingIssue ? "disabled" : ""}>Delete</button>
</div>
`
@@ -606,7 +625,11 @@ function renderSelectedIssueDetail(): string {
}
const draft = state.selectedIssueEditDraft;
const hasChanges = draft.subject !== detail.issue.title || draft.content !== detail.issue.body;
const detailLabels = ISSUE_LABEL_OPTIONS.filter((label) => detail.issue.labels.includes(label));
const hasChanges =
draft.subject !== detail.issue.title ||
draft.content !== detail.issue.body ||
draft.labels.join("|") !== detailLabels.join("|");
return `
<article class="item-card issue-detail-card">
@@ -629,6 +652,7 @@ function renderSelectedIssueDetail(): string {
<span>Content</span>
<textarea id="selected-issue-content" rows="8">${escapeHtml(draft.content)}</textarea>
</label>
${renderLabelOptions(draft.labels, "edit")}
<button id="save-selected-issue" class="primary-button" type="button" ${hasChanges && draft.subject.trim() && !state.isUpdatingIssue ? "" : "disabled"}>
${state.isUpdatingIssue ? "Saving issue..." : "Save issue"}
</button>
@@ -741,6 +765,8 @@ function renderAddIssue(): string {
</select>
</label>
${renderLabelOptions(draft.labels, "draft")}
<section class="attachment-section">
<div class="attachment-heading">
<span>Screenshots</span>
@@ -757,11 +783,6 @@ function renderAddIssue(): string {
</label>
${renderFileList(draft.files, "issue")}
<label class="checkbox-row">
<input id="issue-ready" type="checkbox" ${draft.ready ? "checked" : ""} />
<span>Ready</span>
</label>
<button id="create-issue" class="primary-button" type="button" ${draft.subject.trim() && !state.isCreatingIssue ? "" : "disabled"}>
${state.isCreatingIssue ? "Creating issue..." : "Create issue"}
</button>
@@ -893,12 +914,6 @@ function bindViewActions(): void {
});
});
viewContent?.querySelector<HTMLInputElement>("#issue-ready")?.addEventListener("change", (event) => {
appStore.getState().setIssueDraft({
ready: (event.target as HTMLInputElement).checked
});
});
viewContent?.querySelector<HTMLInputElement>("#issue-files")?.addEventListener("change", (event) => {
const input = event.target as HTMLInputElement;
appStore.getState().setIssueFiles(Array.from(input.files ?? []));
@@ -947,16 +962,6 @@ function bindViewActions(): void {
});
});
viewContent?.querySelectorAll<HTMLButtonElement>("[data-ready-issue]").forEach((button) => {
button.addEventListener("click", () => {
const issueNumber = Number(button.dataset.readyIssue);
const repoFullName = button.dataset.issueRepo;
if (Number.isFinite(issueNumber)) {
void appStore.getState().markIssueReady(issueNumber, repoFullName);
}
});
});
viewContent?.querySelectorAll<HTMLButtonElement>("[data-delete-issue]").forEach((button) => {
button.addEventListener("click", () => {
const issueNumber = Number(button.dataset.deleteIssue);
@@ -991,6 +996,21 @@ function bindViewActions(): void {
void appStore.getState().saveSelectedIssueEdits();
});
viewContent?.querySelectorAll<HTMLInputElement>("[data-label-target]").forEach((input) => {
input.addEventListener("change", () => {
const target = input.dataset.labelTarget;
const labels = Array.from(
viewContent.querySelectorAll<HTMLInputElement>(`input[data-label-target='${target}']:checked`)
).map((checkedInput) => checkedInput.value as IssueLabelOption);
if (target === "draft") {
appStore.getState().setIssueDraft({ labels });
} else if (target === "edit") {
appStore.getState().setSelectedIssueEditDraft({ labels });
}
});
});
viewContent?.querySelectorAll<HTMLButtonElement>("[data-delete-issue-attachment]").forEach((button) => {
button.addEventListener("click", () => {
const attachmentId = Number(button.dataset.deleteIssueAttachment);
@@ -1221,7 +1241,7 @@ function shouldRenderView(): boolean {
}
return !activeElement.matches(
"#issue-subject, #issue-content, #issue-agent, #issue-ready, #selected-issue-subject, #selected-issue-content, #issue-comment-content, #agent-name, #agent-file, #agent-description, #agent-content"
"#issue-subject, #issue-content, #issue-agent, #selected-issue-subject, #selected-issue-content, #issue-comment-content, #agent-name, #agent-file, #agent-description, #agent-content, [data-label-target]"
);
}
@@ -1244,11 +1264,13 @@ function syncFocusedFormControls(): void {
}
if (saveSelectedIssue && state.selectedIssueDetail) {
const detailLabels = ISSUE_LABEL_OPTIONS.filter((label) => state.selectedIssueDetail?.issue.labels.includes(label));
saveSelectedIssue.disabled =
!state.selectedIssueEditDraft.subject.trim() ||
state.isUpdatingIssue ||
(state.selectedIssueEditDraft.subject === state.selectedIssueDetail.issue.title &&
state.selectedIssueEditDraft.content === state.selectedIssueDetail.issue.body);
state.selectedIssueEditDraft.content === state.selectedIssueDetail.issue.body &&
state.selectedIssueEditDraft.labels.join("|") === detailLabels.join("|"));
}
}