mirror of
https://github.com/stablyai/orca.git
synced 2026-10-08 16:02:37 +00:00
Implement GitHub issue close reasons and tabbed comment composer (#5235)
- Support closing GitHub issues with specific reasons ('completed', 'not planned', or duplicate) via main-process mutations and gh CLI wrappers.
- Replace the legacy comment composer with a tabbed layout supporting a real-time markdown preview, image/attachment inputs, and state transition buttons.
- Refactor assignee and label popovers into dedicated reusable components to clean up the item dialog.
This commit is contained in:
@@ -235,10 +235,19 @@ export async function updateIssue(
|
||||
if (updates.state) {
|
||||
await acquire()
|
||||
try {
|
||||
const cmd = updates.state === 'closed' ? 'close' : 'reopen'
|
||||
await ghExecFileAsync(['issue', cmd, String(issueNumber), '--repo', repo], {
|
||||
...ghOptions
|
||||
})
|
||||
if (updates.state === 'closed') {
|
||||
const closeArgs = ['issue', 'close', String(issueNumber), '--repo', repo]
|
||||
if (updates.stateReason === 'completed') {
|
||||
closeArgs.push('--reason', 'completed')
|
||||
} else if (updates.stateReason === 'not_planned') {
|
||||
closeArgs.push('--reason', 'not planned')
|
||||
} else if (updates.stateReason === 'duplicate' && updates.duplicateOf) {
|
||||
closeArgs.push('--duplicate-of', String(updates.duplicateOf))
|
||||
}
|
||||
await ghExecFileAsync(closeArgs, ghOptions)
|
||||
} else {
|
||||
await ghExecFileAsync(['issue', 'reopen', String(issueNumber), '--repo', repo], ghOptions)
|
||||
}
|
||||
} catch (err) {
|
||||
const stderr = err instanceof Error ? err.message : String(err)
|
||||
// Treat "already closed/open" as a no-op
|
||||
|
||||
@@ -171,15 +171,29 @@ export async function updateIssueBySlug(
|
||||
if (!args.updates || typeof args.updates !== 'object') {
|
||||
return { ok: false, error: { type: 'validation_error', message: 'Updates required.' } }
|
||||
}
|
||||
const { title, body, state, addLabels, removeLabels, addAssignees, removeAssignees } =
|
||||
args.updates
|
||||
const {
|
||||
title,
|
||||
body,
|
||||
state,
|
||||
stateReason,
|
||||
duplicateOf,
|
||||
addLabels,
|
||||
removeLabels,
|
||||
addAssignees,
|
||||
removeAssignees
|
||||
} = args.updates
|
||||
|
||||
// Title / body / state go through PATCH /repos/{owner}/{repo}/issues/{n}.
|
||||
// Labels/assignees go through their dedicated endpoints.
|
||||
const base = `repos/${args.owner}/${args.repo}/issues/${args.number}`
|
||||
|
||||
// 1) PATCH body
|
||||
if (title !== undefined || body !== undefined || state !== undefined) {
|
||||
if (
|
||||
title !== undefined ||
|
||||
body !== undefined ||
|
||||
state !== undefined ||
|
||||
stateReason !== undefined
|
||||
) {
|
||||
const patchArgs: string[] = ['-X', 'PATCH', base]
|
||||
if (title !== undefined) {
|
||||
patchArgs.push('--raw-field', `title=${title}`)
|
||||
@@ -190,6 +204,12 @@ export async function updateIssueBySlug(
|
||||
if (state !== undefined) {
|
||||
patchArgs.push('--raw-field', `state=${state}`)
|
||||
}
|
||||
if (stateReason !== undefined) {
|
||||
patchArgs.push('--raw-field', `state_reason=${stateReason}`)
|
||||
}
|
||||
if (duplicateOf !== undefined) {
|
||||
patchArgs.push('--raw-field', `duplicate_of=${duplicateOf}`)
|
||||
}
|
||||
const r = await runRest<unknown>(patchArgs)
|
||||
if (!r.ok) {
|
||||
return { ok: false, error: r.error }
|
||||
|
||||
Reference in New Issue
Block a user