import { SearchIcon } from "lucide-react"; import { PullRequestStackPopover } from "./PullRequestStackPopover"; import { memo, type RefCallback } from "react"; import { cn } from "~/lib/utils"; import { getSourceControlPresentationForKind } from "~/sourceControlPresentation"; import { formatRelativeTimeLabel } from "~/timestampFormat"; import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; import { PullRequestChecksPopover } from "./PullRequestChecksPopover"; import { pullRequestLabelColor, type EnvironmentPullRequestEntry } from "./pullRequestList.logic"; import { openOnHostLabel, showPullRequestLinkContextMenu } from "./pullRequestLinkContextMenu"; import { PullRequestActorLabel, PullRequestDiffStat, PullRequestMetaLine, PullRequestApprovalGlyph, PullRequestStateGlyph, } from "./pullRequestPresentation"; /** * Each slot past the first only appears once the meta line is wide enough to hold it, so a * narrow row shows one label and a "+N" while a wide one spreads out up to three. The "+N" * rides on whichever pill is the last visible one, and is hidden as soon as the next slot shows. */ const LABEL_SLOTS = [ { pill: "", overflow: "@xl/pr-row-meta:hidden" }, { pill: "hidden @xl/pr-row-meta:inline-flex", overflow: "@3xl/pr-row-meta:hidden" }, { pill: "hidden @3xl/pr-row-meta:inline-flex", overflow: "" }, ] as const; function PullRequestRowLabels({ labels }: { labels: EnvironmentPullRequestEntry["labels"] }) { if (labels.length === 0) return null; return ( {LABEL_SLOTS.map((slot, index) => { const label = labels[index]; if (!label) return null; const dot = pullRequestLabelColor(label.color); const remaining = labels.length - index - 1; return ( {label.name} {remaining > 0 ? ( +{remaining} ) : null} ); })} ); } export type PullRequestRowTarget = Pick< EnvironmentPullRequestEntry, "environmentId" | "projectId" | "host" | "repository" | "number" >; function PullRequestRowImpl({ entry, selected, showProjectTitle, showProvider, environmentLabel, matchedElsewhere, statsKey, statsRef, onSelect, }: { entry: EnvironmentPullRequestEntry; selected: boolean; showProjectTitle: boolean; /** Only when the list spans more than one host, where the repository alone is ambiguous. */ showProvider: boolean; /** Names the server this row was read from, where the list spans more than one. */ environmentLabel?: string; /** * A search found this, but in something the row does not show — a description, a comment, a * commit message. Saying so is the difference between a result and an apparently random row. */ matchedElsewhere?: boolean; /** Used by the list's shared visibility observer to defer optional line-count reads. */ statsKey?: string; statsRef?: RefCallback; onSelect: (entry: PullRequestRowTarget) => void; }) { const { Icon, providerName } = getSourceControlPresentationForKind(entry.provider); return ( ); } /** * Memoized: the list re-renders on every keystroke of a search and every status poll, and a * row whose entry, selection and match state are unchanged has nothing new to say. Effective * because the route hands it a stable `onSelect`. */ export const PullRequestRow = memo(PullRequestRowImpl);