"use client"; import { IconAlertTriangle } from "@tabler/icons-react"; import { Button } from "@kandev/ui/button"; import type { MergeableState } from "@/lib/types/github"; // --- Pure descriptor (unit-tested) --- export type MergeabilityNotice = | { kind: "none" } | { kind: "banner" } // dirty / merge conflicts | { kind: "chip"; label: string } // blocked / behind base | { kind: "text" }; // generic non-mergeable fallback /** Maps a PR's merge state to how prominently the panel surfaces it. */ export function describeMergeability({ state, mergeable, isDraft, prState, }: { state: MergeableState | undefined; mergeable: boolean; isDraft: boolean; prState: string; }): MergeabilityNotice { if (prState !== "open" || isDraft) return { kind: "none" }; switch (state) { case "dirty": return { kind: "banner" }; case "blocked": return { kind: "chip", label: "Blocked" }; case "behind": return { kind: "chip", label: "Behind base" }; case "clean": case "unstable": case "has_hooks": case "draft": // "draft" is gated above via isDraft, but handle the enum value too. return { kind: "none" }; default: // unknown / "" / future states: defer to the legacy boolean signal. return mergeable === false ? { kind: "text" } : { kind: "none" }; } } /** Chat-context message sent to the agent when the user clicks "Resolve conflicts". */ export function buildConflictResolutionMessage({ prNumber, headBranch, baseBranch, }: { prNumber: number; headBranch: string; baseBranch: string; }): string { return ( `PR #${prNumber} (\`${headBranch}\` → \`${baseBranch}\`) has merge conflicts and ` + `can't be merged automatically. Please merge \`${baseBranch}\` into \`${headBranch}\` ` + `(or rebase onto it) and resolve the conflicts.` ); } // --- Presentation --- function ConflictBanner({ baseBranch, onResolveConflicts, resolveDisabled, }: { baseBranch: string; onResolveConflicts?: () => void; resolveDisabled?: boolean; }) { return (
Merge conflicts with {baseBranch}

This branch can't be merged automatically. Resolve the conflicts before merging.

{onResolveConflicts && ( )}
); } function MergeabilityChip({ label }: { label: string }) { return ( {label} ); } function NotMergeableText() { return ( Not mergeable ); } export function PRMergeabilityNotice({ state, mergeable, isDraft, prState, baseBranch, onResolveConflicts, resolveDisabled, }: { state: MergeableState | undefined; mergeable: boolean; isDraft: boolean; prState: string; baseBranch: string; onResolveConflicts?: () => void; resolveDisabled?: boolean; }) { const notice = describeMergeability({ state, mergeable, isDraft, prState }); if (notice.kind === "none") return null; if (notice.kind === "banner") return ( ); return (
{notice.kind === "chip" ? : }
); }