import type { Issue } from '../../gitea/types' import { columnLabel, prNumberOf } from './reviewRules' /** PR 改了几个文件:还在读、没读到、读到了。 */ export type FileCount = 'loading' | 'failed' | { count: number } /** 选工单弹框里一项背后的数据;工单没有关联 PR 时没有 pr。 */ export interface PickEntry> { issue: T pr?: { number: number, files: FileCount, hasWorktree: boolean } } /** 弹框里一项的字(QuickPickItem 的 label / description / detail)。 */ export interface PickText { label: string description?: string detail: string } /** 弹框一打开就摆出来的各项:有 PR 的文件数先写「正在读」,读到一个换一个(withFileCount)。 */ export function pickEntries>(issues: readonly T[], hasWorktree: (issue: T) => boolean): PickEntry[] { return issues.map((issue) => { const pr = prNumberOf(issue) return pr === undefined ? { issue } : { issue, pr: { number: pr, files: 'loading', hasWorktree: hasWorktree(issue) } } }) } /** 读到(或没读到)一张工单的 PR 改了几个文件:只换掉那一项,别的项原样(同一个对象),次序不变。 */ export function withFileCount>(entries: readonly PickEntry[], issueNumber: number, files: FileCount): PickEntry[] { return entries.map(entry => entry.issue.number === issueNumber && entry.pr ? { ...entry, pr: { ...entry.pr, files } } : entry) } /** 弹框里的一行:分组标题(列名)或一项。 */ export type PickRow> = { separator: string } | { entry: PickEntry } /** 给按列排好的各项插上分组标题:列一变先插一行列名(没有工单的列不出标题)。 */ export function pickRows>(entries: readonly PickEntry[]): PickRow[] { return entries.flatMap((entry, index) => index > 0 && entries[index - 1].issue.column === entry.issue.column ? [{ entry }] : [{ separator: columnLabel(entry.issue.column) }, { entry }]) } /** 还有 PR 的文件数没读完:弹框接着转圈。 */ export function countingFiles(entries: readonly PickEntry>[]): boolean { return entries.some(entry => entry.pr?.files === 'loading') } /** * 弹框里的一项:第一行工单号 + 标题,后面淡色 PR 号;第二行改了几个文件、本机有没有这张工单的工作副本。 * 没有关联 PR 的第二行只写「没有关联 PR」。 */ export function pickItemText({ issue, pr }: PickEntry>): PickText { const label = `#${issue.number} ${issue.title}` if (!pr) return { label, detail: '没有关联 PR' } const files = pr.files === 'loading' ? '正在读改动文件数…' : pr.files === 'failed' ? '读不到改动文件数' : `改了 ${pr.files.count} 个文件` const worktree = pr.hasWorktree ? '本机有工作副本' : '本机没有工作副本,选中后拉取 PR 分支' return { label, description: `PR #${pr.number}`, detail: `${files} · ${worktree}` } }