authorgravatar for Taras.Fomin@gmail.comTaras <Taras.Fomin@gmail.com> 2026-08-18 23:51:47+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-18 16:51:47-04:00
log26af903b9bec7f8da56bb5f545d9980d08d418e1
treeee8b76eb7160b5364ede14e8ac30afaad84e830e
parentdb0659fead9b7f29f4668c9ba3eb16702c2cff7f
signature Signed by PGP key B5690EEEBB952194

fix(web): label pull request merge actions (#7381)


1 files changed, 26 insertions(+), 12 deletions(-)

apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx+26-12
...@@ -147,6 +147,12 @@ const ACTION_SUCCESS_LABELS: Record<PullRequestAction, string> = {...@@ -147,6 +147,12 @@ const ACTION_SUCCESS_LABELS: Record<PullRequestAction, string> = {
147 "disable-auto-merge": "Auto-merge turned off",147 "disable-auto-merge": "Auto-merge turned off",
148};148};
149149
150const MERGE_METHOD_LABELS: Record<PullRequestMergeMethod, string> = {
151 merge: "Merge",
152 squash: "Squash",
153 rebase: "Rebase",
154};
155
150/** Said as the thing that did not happen, rather than as the operation that returned an error. */156/** Said as the thing that did not happen, rather than as the operation that returned an error. */
151const ACTION_FAILURE_LABELS: Record<PullRequestAction, string> = {157const ACTION_FAILURE_LABELS: Record<PullRequestAction, string> = {
152 merge: "Could not merge this pull request",158 merge: "Could not merge this pull request",
...@@ -460,9 +466,11 @@ export function PullRequestDetailPanel({...@@ -460,9 +466,11 @@ export function PullRequestDetailPanel({
460 if (scroller) scroller.scrollTop = Math.max(0, scroller.scrollTop + delta);466 if (scroller) scroller.scrollTop = Math.max(0, scroller.scrollTop + delta);
461 }, [condensed]);467 }, [condensed]);
462 const [mergeMethod, setMergeMethod] = useState<PullRequestMergeMethod>("merge");468 const [mergeMethod, setMergeMethod] = useState<PullRequestMergeMethod>("merge");
463 const [confirmAction, setConfirmAction] = useState<469 const [confirmation, setConfirmation] = useState<{
464 "merge" | "close" | "enable-auto-merge" | null470 readonly open: boolean;
465 >(null);471 readonly action: "merge" | "close" | "enable-auto-merge";
472 }>({ open: false, action: "merge" });
473 const confirmAction = confirmation.action;
466 // Which handoff is preparing, keyed so a per-finding button can say "Preparing..." on itself474 // Which handoff is preparing, keyed so a per-finding button can say "Preparing..." on itself
467 // alone. One at a time whatever the key: they all check the same pull request out.475 // alone. One at a time whatever the key: they all check the same pull request out.
468 const [handoff, setHandoff] = useState<string | null>(null);476 const [handoff, setHandoff] = useState<string | null>(null);
...@@ -1013,6 +1021,7 @@ export function PullRequestDetailPanel({...@@ -1013,6 +1021,7 @@ export function PullRequestDetailPanel({
1013 const selectedMergeMethod = allowedMergeMethods.includes(mergeMethod)1021 const selectedMergeMethod = allowedMergeMethods.includes(mergeMethod)
1014 ? mergeMethod1022 ? mergeMethod
1015 : (allowedMergeMethods[0] ?? "merge");1023 : (allowedMergeMethods[0] ?? "merge");
1024 const selectedMergeMethodLabel = MERGE_METHOD_LABELS[selectedMergeMethod];
1016 const conflicting = detail?.state === "open" && detail.mergeability === "conflicting";1025 const conflicting = detail?.state === "open" && detail.mergeability === "conflicting";
1017 // Only an outright yes arms it. A host that reports nothing has not said the merge is already1026 // Only an outright yes arms it. A host that reports nothing has not said the merge is already
1018 // spoken for, and an off switch for something that may not be on says the wrong thing twice.1027 // spoken for, and an off switch for something that may not be on says the wrong thing twice.
...@@ -1297,7 +1306,9 @@ export function PullRequestDetailPanel({...@@ -1297,7 +1306,9 @@ export function PullRequestDetailPanel({
1297 allowedMergeMethods.length > 0 ? (1306 allowedMergeMethods.length > 0 ? (
1298 <MenuItem1307 <MenuItem
1299 disabled={actionPending}1308 disabled={actionPending}
1300 onClick={() => setConfirmAction("enable-auto-merge")}1309 onClick={() =>
1310 setConfirmation({ open: true, action: "enable-auto-merge" })
1311 }
1301 >1312 >
1302 <GitMergeIcon className="size-3.5" />1313 <GitMergeIcon className="size-3.5" />
1303 Enable auto-merge1314 Enable auto-merge
...@@ -1326,7 +1337,7 @@ export function PullRequestDetailPanel({...@@ -1326,7 +1337,7 @@ export function PullRequestDetailPanel({
1326 icon and the label need their own row to share a line. */}1337 icon and the label need their own row to share a line. */}
1327 <span className="flex min-w-0 items-center gap-2">1338 <span className="flex min-w-0 items-center gap-2">
1328 <GitMergeIcon className="size-3.5" />1339 <GitMergeIcon className="size-3.5" />
1329 <span className="capitalize">{method}</span>1340 <span>{MERGE_METHOD_LABELS[method]}</span>
1330 </span>1341 </span>
1331 </MenuRadioItem>1342 </MenuRadioItem>
1332 ))}1343 ))}
...@@ -1363,7 +1374,7 @@ export function PullRequestDetailPanel({...@@ -1363,7 +1374,7 @@ export function PullRequestDetailPanel({
1363 <MenuItem1374 <MenuItem
1364 variant="destructive"1375 variant="destructive"
1365 disabled={actionPending}1376 disabled={actionPending}
1366 onClick={() => setConfirmAction("close")}1377 onClick={() => setConfirmation({ open: true, action: "close" })}
1367 >1378 >
1368 <GitPullRequestClosedIcon className="size-3.5" />1379 <GitPullRequestClosedIcon className="size-3.5" />
1369 Close pull request1380 Close pull request
...@@ -1461,9 +1472,9 @@ export function PullRequestDetailPanel({...@@ -1461,9 +1472,9 @@ export function PullRequestDetailPanel({
1461 <Button1472 <Button
1462 size="xs"1473 size="xs"
1463 disabled={actionPending}1474 disabled={actionPending}
1464 onClick={() => setConfirmAction("merge")}1475 onClick={() => setConfirmation({ open: true, action: "merge" })}
1465 >1476 >
1466 {pendingAction === "merge" ? "Merging..." : "Merge"}1477 {pendingAction === "merge" ? "Merging..." : selectedMergeMethodLabel}
1467 </Button>1478 </Button>
1468 ) : null}1479 ) : null}
1469 </>1480 </>
...@@ -1980,8 +1991,11 @@ export function PullRequestDetailPanel({...@@ -1980,8 +1991,11 @@ export function PullRequestDetailPanel({
1980 </div>1991 </div>
19811992
1982 <AlertDialog1993 <AlertDialog
1983 open={confirmAction !== null}1994 open={confirmation.open}
1984 onOpenChange={(open) => !open && setConfirmAction(null)}1995 onOpenChange={(open) => setConfirmation((current) => ({ ...current, open }))}
1996 onOpenChangeComplete={(open) => {
1997 if (!open) setConfirmation({ open: false, action: "merge" });
1998 }}
1985 >1999 >
1986 <AlertDialogPopup>2000 <AlertDialogPopup>
1987 <AlertDialogHeader>2001 <AlertDialogHeader>
...@@ -2013,7 +2027,7 @@ export function PullRequestDetailPanel({...@@ -2013,7 +2027,7 @@ export function PullRequestDetailPanel({
2013 disabled={actionPending}2027 disabled={actionPending}
2014 onClick={() => {2028 onClick={() => {
2015 const action = confirmAction;2029 const action = confirmAction;
2016 setConfirmAction(null);2030 setConfirmation((current) => ({ ...current, open: false }));
2017 if (action === "merge") void perform("merge", selectedMergeMethod);2031 if (action === "merge") void perform("merge", selectedMergeMethod);
2018 if (action === "enable-auto-merge")2032 if (action === "enable-auto-merge")
2019 void perform("enable-auto-merge", selectedMergeMethod);2033 void perform("enable-auto-merge", selectedMergeMethod);
...@@ -2021,7 +2035,7 @@ export function PullRequestDetailPanel({...@@ -2021,7 +2035,7 @@ export function PullRequestDetailPanel({
2021 }}2035 }}
2022 >2036 >
2023 {confirmAction === "merge"2037 {confirmAction === "merge"
2024 ? "Merge"2038 ? selectedMergeMethodLabel
2025 : confirmAction === "enable-auto-merge"2039 : confirmAction === "enable-auto-merge"
2026 ? "Enable auto-merge"2040 ? "Enable auto-merge"
2027 : "Close"}2041 : "Close"}