| ... | @@ -1296,8 +1296,8 @@ export function PullRequestDetailPanel({ | ... | @@ -1296,8 +1296,8 @@ export function PullRequestDetailPanel({ |
| 1296 | | 1296 | |
| 1297 | return ( | 1297 | return ( |
| 1298 | <div className="flex h-full min-h-0 w-full flex-col bg-background"> | 1298 | <div className="flex h-full min-h-0 w-full flex-col bg-background"> |
| 1299 | <div className="grid shrink-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-x-2 border-b border-border/60"> | 1299 | <div className="@container/pr-header grid min-w-0 shrink-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-x-2 border-b border-border/60"> |
| 1300 | <div className="ml-4 grid h-7 min-w-0 items-center"> | 1300 | <div className="ml-4 grid h-7 min-w-0 items-center overflow-hidden"> |
| 1301 | <div | 1301 | <div |
| 1302 | aria-hidden={condensed} | 1302 | aria-hidden={condensed} |
| 1303 | inert={condensed} | 1303 | inert={condensed} |
| ... | @@ -1402,7 +1402,7 @@ export function PullRequestDetailPanel({ | ... | @@ -1402,7 +1402,7 @@ export function PullRequestDetailPanel({ |
| 1402 | ) : null} | 1402 | ) : null} |
| 1403 | </div> | 1403 | </div> |
| 1404 | </div> | 1404 | </div> |
| 1405 | <div className="mr-4 flex h-7 min-w-0 flex-nowrap items-center justify-end gap-1"> | 1405 | <div className="mr-4 flex h-7 shrink-0 items-center justify-end gap-1"> |
| 1406 | {detail ? ( | 1406 | {detail ? ( |
| 1407 | <> | 1407 | <> |
| 1408 | {/* Checking a pull request out is the reason to open one here at all, so it is a | 1408 | {/* Checking a pull request out is the reason to open one here at all, so it is a |
| ... | @@ -1415,9 +1415,17 @@ export function PullRequestDetailPanel({ | ... | @@ -1415,9 +1415,17 @@ export function PullRequestDetailPanel({ |
| 1415 | <MenuTrigger | 1415 | <MenuTrigger |
| 1416 | disabled={handoff !== null} | 1416 | disabled={handoff !== null} |
| 1417 | render={ | 1417 | render={ |
| 1418 | <Button size="xs" variant="outline"> | 1418 | <Button |
| | 1419 | size="xs" |
| | 1420 | variant="outline" |
| | 1421 | aria-label={ |
| | 1422 | handoff?.startsWith("checkout") ? "Checking out..." : "Check out" |
| | 1423 | } |
| | 1424 | > |
| 1419 | <GitBranchIcon aria-hidden className="size-3.5" /> | 1425 | <GitBranchIcon aria-hidden className="size-3.5" /> |
| 1420 | {handoff?.startsWith("checkout") ? "Checking out..." : "Check out"} | 1426 | <span className="@max-[35rem]/pr-header:hidden"> |
| | 1427 | {handoff?.startsWith("checkout") ? "Checking out..." : "Check out"} |
| | 1428 | </span> |
| 1421 | <ChevronDownIcon aria-hidden className="size-3.5 text-muted-foreground" /> | 1429 | <ChevronDownIcon aria-hidden className="size-3.5 text-muted-foreground" /> |
| 1422 | </Button> | 1430 | </Button> |
| 1423 | } | 1431 | } |
| ... | @@ -1453,17 +1461,39 @@ export function PullRequestDetailPanel({ | ... | @@ -1453,17 +1461,39 @@ export function PullRequestDetailPanel({ |
| 1453 | </Menu> | 1461 | </Menu> |
| 1454 | ) : null} | 1462 | ) : null} |
| 1455 | {workflowApprovalsRequired > 0 && can("approve-workflows") ? ( | 1463 | {workflowApprovalsRequired > 0 && can("approve-workflows") ? ( |
| 1456 | <Button | 1464 | <Tooltip> |
| 1457 | size="xs" | 1465 | <TooltipTrigger |
| 1458 | variant="warning-outline" | 1466 | render={ |
| 1459 | disabled={actionPending} | 1467 | <span className="inline-flex shrink-0"> |
| 1460 | onClick={() => setConfirmation({ open: true, action: "approve-workflows" })} | 1468 | <Button |
| 1461 | > | 1469 | size="xs" |
| 1462 | <PlayIcon className="size-3.5" /> | 1470 | variant="warning-outline" |
| 1463 | {pendingAction === "approve-workflows" | 1471 | disabled={actionPending} |
| 1464 | ? "Approving..." | 1472 | onClick={() => |
| 1465 | : "Approve workflows to run"} | 1473 | setConfirmation({ open: true, action: "approve-workflows" }) |
| 1466 | </Button> | 1474 | } |
| | 1475 | aria-label={ |
| | 1476 | pendingAction === "approve-workflows" |
| | 1477 | ? "Approving..." |
| | 1478 | : "Approve workflows to run" |
| | 1479 | } |
| | 1480 | > |
| | 1481 | <PlayIcon aria-hidden className="size-3.5" /> |
| | 1482 | <span className="@max-[40rem]/pr-header:hidden"> |
| | 1483 | {pendingAction === "approve-workflows" |
| | 1484 | ? "Approving..." |
| | 1485 | : "Approve workflows to run"} |
| | 1486 | </span> |
| | 1487 | </Button> |
| | 1488 | </span> |
| | 1489 | } |
| | 1490 | /> |
| | 1491 | <TooltipPopup side="top"> |
| | 1492 | {pendingAction === "approve-workflows" |
| | 1493 | ? "Approving..." |
| | 1494 | : "Approve workflows to run"} |
| | 1495 | </TooltipPopup> |
| | 1496 | </Tooltip> |
| 1467 | ) : null} | 1497 | ) : null} |
| 1468 | {/* Said where the Merge button is, because it is the answer to why nobody has | 1498 | {/* Said where the Merge button is, because it is the answer to why nobody has |
| 1469 | pressed it: the merge is already asked for, and the host is holding it. */} | 1499 | pressed it: the merge is already asked for, and the host is holding it. */} |
| ... | @@ -1471,62 +1501,150 @@ export function PullRequestDetailPanel({ | ... | @@ -1471,62 +1501,150 @@ export function PullRequestDetailPanel({ |
| 1471 | <Tooltip> | 1501 | <Tooltip> |
| 1472 | <TooltipTrigger | 1502 | <TooltipTrigger |
| 1473 | render={ | 1503 | render={ |
| 1474 | <Badge size="control" variant="info"> | 1504 | <Badge |
| | 1505 | size="control" |
| | 1506 | variant="info" |
| | 1507 | role="img" |
| | 1508 | aria-label={armedAutoMergeLabel} |
| | 1509 | > |
| 1475 | <GitMergeIcon aria-hidden className="size-3.5" /> | 1510 | <GitMergeIcon aria-hidden className="size-3.5" /> |
| 1476 | {armedAutoMergeLabel} | 1511 | <span className="@max-[30rem]/pr-header:hidden">{armedAutoMergeLabel}</span> |
| 1477 | </Badge> | 1512 | </Badge> |
| 1478 | } | 1513 | } |
| 1479 | /> | 1514 | /> |
| 1480 | <TooltipPopup side="top"> | 1515 | <TooltipPopup side="top"> |
| 1481 | The host will merge this on its own once its requirements are met | 1516 | {armedAutoMergeLabel}: the host will merge this on its own once its requirements |
| | 1517 | are met |
| 1482 | </TooltipPopup> | 1518 | </TooltipPopup> |
| 1483 | </Tooltip> | 1519 | </Tooltip> |
| 1484 | ) : null} | 1520 | ) : null} |
| 1485 | {primaryAction === "resolve" ? ( | 1521 | {primaryAction === "resolve" ? ( |
| 1486 | <Button | 1522 | <Tooltip> |
| 1487 | size="xs" | 1523 | <TooltipTrigger |
| 1488 | variant="destructive-outline" | 1524 | render={ |
| 1489 | disabled={handoff !== null} | 1525 | <span className="inline-flex shrink-0"> |
| 1490 | onClick={startResolveConflicts} | 1526 | <Button |
| 1491 | > | 1527 | size="xs" |
| 1492 | <TriangleAlertIcon className="size-3.5" /> | 1528 | variant="destructive-outline" |
| 1493 | {handoff === "conflicts" ? "Preparing..." : "Resolve conflicts"} | 1529 | disabled={handoff !== null} |
| 1494 | </Button> | 1530 | onClick={startResolveConflicts} |
| | 1531 | aria-label={ |
| | 1532 | handoff === "conflicts" ? "Preparing..." : "Resolve conflicts" |
| | 1533 | } |
| | 1534 | > |
| | 1535 | <TriangleAlertIcon aria-hidden className="size-3.5" /> |
| | 1536 | <span className="@max-[30rem]/pr-header:hidden"> |
| | 1537 | {handoff === "conflicts" ? "Preparing..." : "Resolve conflicts"} |
| | 1538 | </span> |
| | 1539 | </Button> |
| | 1540 | </span> |
| | 1541 | } |
| | 1542 | /> |
| | 1543 | <TooltipPopup side="top"> |
| | 1544 | {handoff === "conflicts" ? "Preparing..." : "Resolve conflicts"} |
| | 1545 | </TooltipPopup> |
| | 1546 | </Tooltip> |
| 1495 | ) : primaryAction === "ready" ? ( | 1547 | ) : primaryAction === "ready" ? ( |
| 1496 | <Button size="xs" disabled={actionPending} onClick={() => void perform("ready")}> | 1548 | <Tooltip> |
| 1497 | Ready for review | 1549 | <TooltipTrigger |
| 1498 | </Button> | 1550 | render={ |
| | 1551 | <span className="inline-flex shrink-0"> |
| | 1552 | <Button |
| | 1553 | size="xs" |
| | 1554 | disabled={actionPending} |
| | 1555 | onClick={() => void perform("ready")} |
| | 1556 | aria-label="Ready for review" |
| | 1557 | > |
| | 1558 | <GitPullRequestIcon |
| | 1559 | aria-hidden |
| | 1560 | className="hidden size-3.5 @max-[30rem]/pr-header:inline" |
| | 1561 | /> |
| | 1562 | <span className="@max-[30rem]/pr-header:hidden">Ready for review</span> |
| | 1563 | </Button> |
| | 1564 | </span> |
| | 1565 | } |
| | 1566 | /> |
| | 1567 | <TooltipPopup side="top">Ready for review</TooltipPopup> |
| | 1568 | </Tooltip> |
| 1499 | ) : primaryAction === "enable-auto-merge" ? ( | 1569 | ) : primaryAction === "enable-auto-merge" ? ( |
| 1500 | <Button | 1570 | <Tooltip> |
| 1501 | size="xs" | 1571 | <TooltipTrigger |
| 1502 | disabled={actionPending} | 1572 | render={ |
| 1503 | onClick={() => setConfirmation({ open: true, action: "enable-auto-merge" })} | 1573 | <span className="inline-flex shrink-0"> |
| 1504 | > | 1574 | <Button |
| 1505 | <GitMergeIcon className="size-3.5" /> | 1575 | size="xs" |
| 1506 | {pendingAction === "enable-auto-merge" ? "Enabling..." : pendingAutoMergeLabel} | 1576 | disabled={actionPending} |
| 1507 | </Button> | 1577 | onClick={() => |
| | 1578 | setConfirmation({ open: true, action: "enable-auto-merge" }) |
| | 1579 | } |
| | 1580 | aria-label={ |
| | 1581 | pendingAction === "enable-auto-merge" |
| | 1582 | ? "Enabling..." |
| | 1583 | : pendingAutoMergeLabel |
| | 1584 | } |
| | 1585 | > |
| | 1586 | <GitMergeIcon aria-hidden className="size-3.5" /> |
| | 1587 | <span className="@max-[30rem]/pr-header:hidden"> |
| | 1588 | {pendingAction === "enable-auto-merge" |
| | 1589 | ? "Enabling..." |
| | 1590 | : pendingAutoMergeLabel} |
| | 1591 | </span> |
| | 1592 | </Button> |
| | 1593 | </span> |
| | 1594 | } |
| | 1595 | /> |
| | 1596 | <TooltipPopup side="top"> |
| | 1597 | {pendingAction === "enable-auto-merge" ? "Enabling..." : pendingAutoMergeLabel} |
| | 1598 | </TooltipPopup> |
| | 1599 | </Tooltip> |
| 1508 | ) : primaryAction === "auto-merge-armed" ? ( | 1600 | ) : primaryAction === "auto-merge-armed" ? ( |
| 1509 | <Tooltip> | 1601 | <Tooltip> |
| 1510 | <TooltipTrigger | 1602 | <TooltipTrigger |
| 1511 | render={ | 1603 | render={ |
| 1512 | <Badge size="control" variant="info"> | 1604 | <Badge |
| 1513 | <GitMergeIcon className="size-3.5" /> | 1605 | size="control" |
| 1514 | {armedAutoMergeLabel} | 1606 | variant="info" |
| | 1607 | role="img" |
| | 1608 | aria-label={armedAutoMergeLabel} |
| | 1609 | > |
| | 1610 | <GitMergeIcon aria-hidden className="size-3.5" /> |
| | 1611 | <span className="@max-[30rem]/pr-header:hidden">{armedAutoMergeLabel}</span> |
| 1515 | </Badge> | 1612 | </Badge> |
| 1516 | } | 1613 | } |
| 1517 | /> | 1614 | /> |
| 1518 | <TooltipPopup side="top"> | 1615 | <TooltipPopup side="top"> |
| 1519 | The host will merge this on its own once its requirements are met | 1616 | {armedAutoMergeLabel}: the host will merge this on its own once its requirements |
| | 1617 | are met |
| 1520 | </TooltipPopup> | 1618 | </TooltipPopup> |
| 1521 | </Tooltip> | 1619 | </Tooltip> |
| 1522 | ) : primaryAction === "merge" ? ( | 1620 | ) : primaryAction === "merge" ? ( |
| 1523 | <Button | 1621 | <Tooltip> |
| 1524 | size="xs" | 1622 | <TooltipTrigger |
| 1525 | disabled={actionPending} | 1623 | render={ |
| 1526 | onClick={() => setConfirmation({ open: true, action: "merge" })} | 1624 | <span className="inline-flex shrink-0"> |
| 1527 | > | 1625 | <Button |
| 1528 | {pendingAction === "merge" ? "Merging..." : selectedMergeMethodLabel} | 1626 | size="xs" |
| 1529 | </Button> | 1627 | disabled={actionPending} |
| | 1628 | onClick={() => setConfirmation({ open: true, action: "merge" })} |
| | 1629 | aria-label={ |
| | 1630 | pendingAction === "merge" ? "Merging..." : selectedMergeMethodLabel |
| | 1631 | } |
| | 1632 | > |
| | 1633 | <GitMergeIcon |
| | 1634 | aria-hidden |
| | 1635 | className="hidden size-3.5 @max-[30rem]/pr-header:inline" |
| | 1636 | /> |
| | 1637 | <span className="@max-[30rem]/pr-header:hidden"> |
| | 1638 | {pendingAction === "merge" ? "Merging..." : selectedMergeMethodLabel} |
| | 1639 | </span> |
| | 1640 | </Button> |
| | 1641 | </span> |
| | 1642 | } |
| | 1643 | /> |
| | 1644 | <TooltipPopup side="top"> |
| | 1645 | {pendingAction === "merge" ? "Merging..." : selectedMergeMethodLabel} |
| | 1646 | </TooltipPopup> |
| | 1647 | </Tooltip> |
| 1530 | ) : (primaryAction === "merged" || primaryAction === "closed") && | 1648 | ) : (primaryAction === "merged" || primaryAction === "closed") && |
| 1531 | statePresentation !== null ? ( | 1649 | statePresentation !== null ? ( |
| 1532 | <Badge size="control" variant="outline" className={statePresentation.toneClassName}> | 1650 | <Badge size="control" variant="outline" className={statePresentation.toneClassName}> |
| ... | @@ -1857,10 +1975,17 @@ export function PullRequestDetailPanel({ | ... | @@ -1857,10 +1975,17 @@ export function PullRequestDetailPanel({ |
| 1857 | {detail ? ( | 1975 | {detail ? ( |
| 1858 | <div className="col-span-2 mt-1 min-w-0 px-4 pb-4"> | 1976 | <div className="col-span-2 mt-1 min-w-0 px-4 pb-4"> |
| 1859 | {titleDraft === null ? ( | 1977 | {titleDraft === null ? ( |
| 1860 | <div className="group flex min-w-0 items-start gap-1"> | 1978 | <div className="group flex min-w-0 items-center gap-1"> |
| 1861 | <h1 className="min-w-0 flex-1 text-base font-semibold leading-snug"> | 1979 | <Tooltip> |
| 1862 | {detail.title} | 1980 | <TooltipTrigger |
| 1863 | </h1> | 1981 | render={ |
| | 1982 | <h1 className="min-w-0 flex-1 truncate text-base font-semibold leading-snug"> |
| | 1983 | {detail.title} |
| | 1984 | </h1> |
| | 1985 | } |
| | 1986 | /> |
| | 1987 | <TooltipPopup side="top">{detail.title}</TooltipPopup> |
| | 1988 | </Tooltip> |
| 1864 | {canEditPullRequestChangeRequest(detail) ? ( | 1989 | {canEditPullRequestChangeRequest(detail) ? ( |
| 1865 | <Button | 1990 | <Button |
| 1866 | size="icon-xs" | 1991 | size="icon-xs" |