MergeBox
uses tcmts.share.shareNow, which uses process
Whether it merges, and what the viewer may do about it: merge (the maintainer), close or reopen (theirs too).
import type { Mergeable } from "#codebase/tcmts/cli/contributions"; import { shortHash } from "#codebase/tcmts/core/hash"; import { ActButton, at, shareNow } from "#codebase/tcmts/share"; import type { Contribution } from "#codebase/tcmts/store"; import { Link } from "react-aria-components"; export function MergeBox({ c, m, tests }: { c: Contribution; m: Mergeable | null; tests: number }) { const s = shareNow(); const mine = s.caller.role === "maintainer" || (s.caller.role === "contributor" && c.source.startsWith(`@${s.caller.handle}/`)); if (c.status === "merged") return ( <div className="mergebox"> <span className="big">⑂</span> <div> <b> Merged into <code>{c.target}</code> </b> <div className="muted"> as <a className="hash" href={at(`/history/${c.mergedAs ?? ""}`)}>{shortHash(c.mergedAs ?? "")}</a> </div> </div> </div> ); if (c.status === "closed") return ( <div className="mergebox"> <span className="big">✕</span> <div> <b>Closed without merging</b> </div> {mine && ( <span className="right"> <ActButton id={c.id} what="reopen" label="Reopen" /> </span> )} </div> ); const good = !!m && m.kind !== "conflicts"; const title = !m ? "Its branches are gone" : m.kind === "conflicts" ? `Conflicts with ${c.target}` : m.kind === "up-to-date" ? `${c.target} already has these changes` : m.kind === "fast-forward" ? "Merges as a fast-forward" : "Merges cleanly"; const detail = !m ? "" : m.kind === "conflicts" ? `In ${m.names.join(", ")}. The contributor brings ${c.target} in (tcm pull origin ${c.target} on the branch), settles them, and pushes again.` : `${m.kind === "clean" && m.asText?.length ? `${m.asText.join(", ")} merged as text: tried, and checked to typecheck, before it lands. ` : "No conflicts. "}${tests ? `${tests} test${tests > 1 ? "s" : ""} reach this change: they run again wherever it's pulled.` : ""}`; return ( <div className={`mergebox ${good ? "good" : "blocked"}`}> <span className={`big ${good ? "ok" : "bad"}`}>{good ? "✓" : "✕"}</span> <div> <b>{title}</b> <div className="muted">{detail}</div> </div> <span className="right" style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}> {s.caller.role === "maintainer" && good && <ActButton id={c.id} what="merge" label={`Merge into ${c.target}`} kind="primary" />} {mine && <ActButton id={c.id} what="close" label="Close" kind="danger" />} {s.caller.role === "reader" && ( <Link className="btn" href={at(`/sign-in?then=${encodeURIComponent(`/contributions/${c.id}`)}`)}> Sign in to review </Link> )} </span> </div> ); }
uses
- tcmts.cli.contributions.Mergeable
- tcmts.core.hash.shortHash
- tcmts.share.ActButton
- tcmts.share.at
- tcmts.share.shareNow
- tcmts.store.Contribution