import type { ChangedFile, MergeMethod, PullState, ReviewState, ReviewerState, UserDto } from '@/entities/pull-request' import type { DiffFile, DiffFileStatus } from '@/entities/repo' /** UI-only filter: the backend understands open/closed/merged and no filter. */ export type PullFilter = PullState | 'all' | 'draft' export const PULL_STATE_LABEL: Record = { open: '待合并', closed: '已关闭', merged: '已合并', } /** tailwind-ish tone classes shared across badges (mirrors repo-history colors). */ export const TONE = { green: 'text-[#1a7f37] bg-[rgba(35,165,90,0.12)]', red: 'text-[#b42318] bg-[rgba(242,63,67,0.10)]', amber: 'text-[#8a6100] bg-[rgba(240,178,50,0.16)]', violet: 'text-[#6937c3] bg-[rgba(120,82,196,0.12)]', gray: 'text-shell-ink-muted bg-shell-active', } as const export const REVIEW_STATE_LABEL: Record = { approved: '已批准', changes_requested: '请求修改', commented: '评论', pending: '待提交', dismissed: '已撤销', } export const REVIEW_STATE_TONE: Record = { approved: 'green', changes_requested: 'red', commented: 'gray', pending: 'amber', dismissed: 'gray', } export const REVIEWER_STATE_LABEL: Record = { requested: '待评审', approved: '已批准', changes_requested: '请求修改', commented: '已评论', dismissed: '已撤销', } export const MERGE_METHOD_LABEL: Record = { merge: '普通合并', squash: '压缩合并', rebase: '变基合并', } /** The backend formats status with `{:?}` (Debug names) — normalize loosely. */ export function normalizeFileStatus(raw: string): DiffFileStatus { const s = raw.toLowerCase() if (s.startsWith('ad') || s.startsWith('new') || s.startsWith('creat') || s === 'a') return 'added' if (s.startsWith('del') || s.startsWith('rem') || s === 'd') return 'deleted' if (s.startsWith('ren') || s.startsWith('mov') || s === 'r') return 'renamed' if (s.startsWith('cop') || s === 'c') return 'copied' if (s.startsWith('bin')) return 'binary' return 'modified' } const EVENT_LABEL: Record = { created: '创建了本合并请求', updated: '更新了合并请求', title_changed: '修改了标题', body_edited: '编辑了描述', base_changed: '改动了目标分支', marked_ready: '转为正式合并请求', marked_draft: '转为草稿', closed: '关闭了合并请求', reopened: '重新打开了合并请求', merged: '合并了本合并请求', review_requested: '请求了评审', review_request_removed: '移除了评审请求', review_submitted: '提交了评审', approved: '批准了本合并请求', changes_requested: '请求修改', comment: '发表了评论', labeled: '添加了标签', unlabeled: '移除了标签', assigned: '添加了受理人', unassigned: '移除了受理人', locked: '锁定了讨论', unlocked: '解锁了讨论', force_push: '向源分支强推了提交', branch_updated: '同步了目标分支', head_ref_updated: '更新了源分支', auto_merge_enabled: '开启了自动合并', auto_merge_disabled: '关闭了自动合并', } export const eventLabel = (eventType: string): string => EVENT_LABEL[eventType] ?? eventType.replaceAll('_', ' ') export const userName = (user?: UserDto | null): string => user?.display_name || user?.username || '未知用户' export interface InlineAnchor { path: string line: number side: 'left' | 'right' } export const anchorKey = (path: string, line: number, side: 'left' | 'right') => `${path}#${side}${line}` /** A pinned inline comment as rendered under its diff line. */ export interface AnchoredComment { id: string body: string } export function changedFileToDiff(file: ChangedFile): DiffFile { const status = file.binary ? 'binary' : normalizeFileStatus(file.path.status) return { path: file.path.new_path, oldPath: file.path.old_path && file.path.old_path !== file.path.new_path ? file.path.old_path : null, status, raw: file.patch ?? '', additions: file.lines_added, deletions: file.lines_removed, } }