1import {
2 isMergebotRepository,
3 mergebotPullRequestStatus,
4 type EnvironmentId,
5} from "@t3tools/contracts";
6
7import { useMergebotQueue } from "../../state/mergebot";
8import { useEnvironment } from "../../state/environments";
9import { Badge } from "../ui/badge";
10import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
11
12const PHASE_LABEL = {
13 not_queued: "Not queued",
14 queued: "Queued",
15 updating_branch: "Updating branch",
16 waiting_ci: "Waiting for CI",
17 merging: "Merging",
18 ci_failed: "CI failed",
19} as const;
20
21interface Props {
22 environmentId: EnvironmentId;
23 repository: string;
24 number: number;
25 headSha?: string | undefined;
26}
27
28export function MergebotQueueBadge(props: Props) {
29 const configuration = useEnvironment(props.environmentId)?.serverConfig?.mergebot;
30 return isMergebotRepository(configuration, props.repository) ? (
31 <SupportedQueueBadge {...props} />
32 ) : null;
33}
34
35function SupportedQueueBadge({ environmentId, repository, number, headSha }: Props) {
36 const queue = useMergebotQueue(environmentId, repository);
37 const entry = mergebotPullRequestStatus(queue, number, headSha);
38 const phase = entry?.lifecycle === "open" ? entry.queueStatus : null;
39 const held = phase !== null && phase !== "not_queued" && entry?.position === null;
40 const label = phase
41 ? `${PHASE_LABEL[phase]}${entry?.position ? ` #${entry.position}` : held ? " (held)" : ""}`
42 : "Unknown";
43 const variant =
44 phase === "ci_failed"
45 ? "error"
46 : held
47 ? "warning"
48 : phase && phase !== "not_queued"
49 ? "info"
50 : "secondary";
51
52 return (
53 <Tooltip>
54 <TooltipTrigger
55 render={
56 <Badge size="sm" variant={variant} aria-label={`Mergebot: ${label}`} role="status" />
57 }
58 >
59 Mergebot: {label}
60 </TooltipTrigger>
61 <TooltipPopup>
62 {phase ? `Mergebot: ${label}` : "Mergebot queue status unavailable for this revision."}
63 </TooltipPopup>
64 </Tooltip>
65 );
66}