| ... | @@ -849,6 +849,9 @@ export function PullRequestDetailPanel({ | ... | @@ -849,6 +849,9 @@ export function PullRequestDetailPanel({ |
| 849 | // and at worst answer from it. | 849 | // and at worst answer from it. |
| 850 | const invalidate = useAtomCommand(pullRequestEnvironment.invalidate, { reportFailure: false }); | 850 | const invalidate = useAtomCommand(pullRequestEnvironment.invalidate, { reportFailure: false }); |
| 851 | const [isInvalidating, setIsInvalidating] = useState(false); | 851 | const [isInvalidating, setIsInvalidating] = useState(false); |
| | 852 | // One word for "the host is being asked again", whichever of the two halves is in flight: |
| | 853 | // the invalidation round trip, then the detail read it kicks off. |
| | 854 | const refreshing = isInvalidating || detailQuery.isPending; |
| 852 | const refreshFromHost = useCallback(async () => { | 855 | const refreshFromHost = useCallback(async () => { |
| 853 | setIsInvalidating(true); | 856 | setIsInvalidating(true); |
| 854 | try { | 857 | try { |
| ... | @@ -1987,18 +1990,29 @@ export function PullRequestDetailPanel({ | ... | @@ -1987,18 +1990,29 @@ export function PullRequestDetailPanel({ |
| 1987 | <MenuTrigger | 1990 | <MenuTrigger |
| 1988 | render={ | 1991 | render={ |
| 1989 | <Button | 1992 | <Button |
| 1990 | aria-label="More pull request actions" | 1993 | aria-label={ |
| | 1994 | refreshing ? "Refreshing pull request" : "More pull request actions" |
| | 1995 | } |
| 1991 | className="size-6" | 1996 | className="size-6" |
| 1992 | size="icon-xs" | 1997 | size="icon-xs" |
| 1993 | variant="ghost-muted" | 1998 | variant="ghost-muted" |
| 1994 | /> | 1999 | /> |
| 1995 | } | 2000 | } |
| 1996 | > | 2001 | > |
| 1997 | <MoreHorizontalIcon className="size-4" /> | 2002 | {/* The refresh lives in this menu, so while one runs the trigger wears |
| | 2003 | the spinning glyph in place of the dots: the reader sees the panel |
| | 2004 | is fetching without a control appearing or the row shifting. */} |
| | 2005 | {refreshing ? ( |
| | 2006 | <RefreshIcon refreshing className="size-4" /> |
| | 2007 | ) : ( |
| | 2008 | <MoreHorizontalIcon className="size-4" /> |
| | 2009 | )} |
| 1998 | </MenuTrigger> | 2010 | </MenuTrigger> |
| 1999 | } | 2011 | } |
| 2000 | /> | 2012 | /> |
| 2001 | <TooltipPopup>More pull request actions</TooltipPopup> | 2013 | <TooltipPopup> |
| | 2014 | {refreshing ? "Refreshing pull request" : "More pull request actions"} |
| | 2015 | </TooltipPopup> |
| 2002 | </Tooltip> | 2016 | </Tooltip> |
| 2003 | <MenuPopup align="end" side="bottom" className="min-w-72"> | 2017 | <MenuPopup align="end" side="bottom" className="min-w-72"> |
| 2004 | <PullRequestThreadLinks | 2018 | <PullRequestThreadLinks |
| ... | @@ -2012,14 +2026,8 @@ export function PullRequestDetailPanel({ | ... | @@ -2012,14 +2026,8 @@ export function PullRequestDetailPanel({ |
| 2012 | } | 2026 | } |
| 2013 | onPickerOpenChange={setThreadPickerOpen} | 2027 | onPickerOpenChange={setThreadPickerOpen} |
| 2014 | /> | 2028 | /> |
| 2015 | <MenuItem | 2029 | <MenuItem disabled={refreshing} onClick={() => void refreshFromHost()}> |
| 2016 | disabled={isInvalidating || detailQuery.isPending} | 2030 | <RefreshIcon className="size-3.5" refreshing={refreshing} /> |
| 2017 | onClick={() => void refreshFromHost()} | | |
| 2018 | > | | |
| 2019 | <RefreshIcon | | |
| 2020 | className="size-3.5" | | |
| 2021 | refreshing={isInvalidating || detailQuery.isPending} | | |
| 2022 | /> | | |
| 2023 | Refresh | 2031 | Refresh |
| 2024 | </MenuItem> | 2032 | </MenuItem> |
| 2025 | <MenuItem disabled={handoff !== null} onClick={askAboutPullRequest}> | 2033 | <MenuItem disabled={handoff !== null} onClick={askAboutPullRequest}> |