"use client"; import { IconAlertTriangle, IconCheck, IconCircleDot, IconClockHour4, IconGitMerge, IconGitPullRequest, IconGitPullRequestDraft, IconX, type Icon as TablerIcon, } from "@tabler/icons-react"; import type { TFunction } from "i18next"; import { useTranslation } from "react-i18next"; import { cn } from "@/lib/utils"; import type { TaskPR } from "@/lib/types/github"; export type PRTaskSummaryRowKind = "state" | "review" | "ci" | "merge"; export type PRTaskSummaryTone = "success" | "danger" | "warning" | "info" | "merged" | "muted"; export type PRTaskSummaryStatus = | "merged" | "closed" | "approved" | "changes_requested" | "pending_review" | "passed" | "failed" | "in_progress" | "draft" | "ready" | "conflicts" | "behind" | "blocked" | "mergeable" | "raw"; export type PRTaskSummaryRow = { kind: PRTaskSummaryRowKind; status: PRTaskSummaryStatus; tone: PRTaskSummaryTone; rawValue?: string; }; export type PRTaskStatusSummaryData = { number: number; title: string; rows: PRTaskSummaryRow[]; }; function rawRow(kind: PRTaskSummaryRowKind, rawValue: string): PRTaskSummaryRow { return { kind, status: "raw", tone: "muted", rawValue }; } function deriveStateRow(state: string): PRTaskSummaryRow | null { if (!state || state === "open") return null; if (state === "merged") return { kind: "state", status: "merged", tone: "merged" }; if (state === "closed") return { kind: "state", status: "closed", tone: "danger" }; return rawRow("state", state); } function deriveReviewRow(reviewState: string): PRTaskSummaryRow | null { if (!reviewState) return null; if (reviewState === "approved") { return { kind: "review", status: "approved", tone: "success" }; } if (reviewState === "changes_requested") { return { kind: "review", status: "changes_requested", tone: "danger" }; } if (reviewState === "pending") { return { kind: "review", status: "pending_review", tone: "info" }; } return rawRow("review", reviewState); } function deriveCIRow(checksState: string): PRTaskSummaryRow | null { if (!checksState) return null; if (checksState === "success") return { kind: "ci", status: "passed", tone: "success" }; if (checksState === "failure") return { kind: "ci", status: "failed", tone: "danger" }; if (checksState === "pending") { return { kind: "ci", status: "in_progress", tone: "warning" }; } return rawRow("ci", checksState); } function deriveMergeRow(pr: TaskPR, readyToMerge: boolean): PRTaskSummaryRow | null { if (pr.state !== "open") return null; if (pr.mergeable_state === "draft") { return { kind: "merge", status: "draft", tone: "muted" }; } if (readyToMerge) return { kind: "merge", status: "ready", tone: "success" }; if (!pr.mergeable_state || pr.mergeable_state === "unknown") return null; if (pr.mergeable_state === "dirty") { return { kind: "merge", status: "conflicts", tone: "danger" }; } if (pr.mergeable_state === "behind") { return { kind: "merge", status: "behind", tone: "warning" }; } if (pr.mergeable_state === "blocked") { return { kind: "merge", status: "blocked", tone: "muted" }; } if (pr.mergeable_state === "clean") { return { kind: "merge", status: "mergeable", tone: "muted" }; } return rawRow("merge", pr.mergeable_state); } export function derivePRTaskStatusSummary( pr: TaskPR, readyToMerge: boolean, ): PRTaskStatusSummaryData { const rows = [ deriveStateRow(pr.state), deriveReviewRow(pr.review_state), deriveCIRow(pr.checks_state), deriveMergeRow(pr, readyToMerge), ].filter((row): row is PRTaskSummaryRow => row !== null); return { number: pr.pr_number, title: pr.pr_title, rows }; } const ROW_LABEL_KEYS: Record = { state: "github:prTaskStatusState", review: "github:prTaskStatusReview", ci: "github:prTaskStatusCi", merge: "github:prTaskStatusMerge", }; const TONE_CLASSES: Record = { success: "text-emerald-600 dark:text-emerald-400", danger: "text-red-600 dark:text-red-400", warning: "text-amber-600 dark:text-amber-400", info: "text-sky-600 dark:text-sky-400", merged: "text-purple-600 dark:text-purple-400", muted: "text-muted-foreground", }; const STATUS_LABEL_KEYS: Record, string> = { merged: "github:merged", closed: "github:closed", approved: "github:approved", changes_requested: "github:changesRequested", pending_review: "github:pendingReview", passed: "github:checkBucketPassed", failed: "github:checkBucketFailed", in_progress: "github:checkBucketInProgress", draft: "github:draft", ready: "github:readyToMerge", conflicts: "github:conflicts", behind: "github:behindBase", blocked: "github:blocked", mergeable: "github:mergeable", }; const STATUS_ICONS: Record = { merged: IconGitMerge, closed: IconX, approved: IconCheck, changes_requested: IconX, pending_review: IconClockHour4, passed: IconCheck, failed: IconX, in_progress: IconClockHour4, draft: IconGitPullRequestDraft, ready: IconGitMerge, conflicts: IconAlertTriangle, behind: IconAlertTriangle, blocked: IconAlertTriangle, mergeable: IconGitMerge, raw: IconCircleDot, }; function getStatusText(row: PRTaskSummaryRow, t: TFunction): string { if (row.status === "raw") return row.rawValue ?? ""; return t(STATUS_LABEL_KEYS[row.status]); } function SummaryStatusIcon({ status }: { status: PRTaskSummaryStatus }) { const StatusIcon = STATUS_ICONS[status]; return