feat: refactor <ProxyMenu /> (#21807)

This pull-request takes the old `<ProxyMenu />` in the header and makes
it so that we're inline with the latest and greatest of components from
codebase rather than MUI. Furthermore, we're reintroducing the
`<DropdownRadioGroup />` and `<DropdownRadioItem />` components.

<img width="3516" height="2390" alt="CleanShot 2026-01-31 at 13 49
28@2x"
src="https://github.com/user-attachments/assets/7f8de8e9-7645-446e-9495-0b20194cc759"
/>

### Preview

| Old | New |
| --- | --- |
| <img width="418" height="499" alt="LATENCY_OLD"
src="https://github.com/user-attachments/assets/86e9166a-7045-48c9-91f1-4593f85274d4"
/> | <img width="418" height="499" alt="LATENCY_NEW"
src="https://github.com/user-attachments/assets/a1cf80af-d11f-4bc7-99fd-a41c54a7b153"
/> |
This commit is contained in:
Jake Howell
2026-02-03 23:16:55 +11:00
committed by GitHub
parent 4fe64213c3
commit 912fbab11a
2 changed files with 125 additions and 164 deletions
@@ -7,7 +7,7 @@
*/
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { Check, ChevronRight, Circle } from "lucide-react";
import { Check, ChevronRight } from "lucide-react";
import {
type ComponentPropsWithoutRef,
type ElementRef,
@@ -26,7 +26,7 @@ const _DropdownMenuPortal = DropdownMenuPrimitive.Portal;
const _DropdownMenuSub = DropdownMenuPrimitive.Sub;
const _DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = forwardRef<
ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
@@ -154,7 +154,7 @@ const DropdownMenuCheckboxItem = forwardRef<
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = forwardRef<
export const DropdownMenuRadioItem = forwardRef<
ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
@@ -162,19 +162,20 @@ const DropdownMenuRadioItem = forwardRef<
ref={ref}
className={cn(
[
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors",
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pr-8 pl-2 text-sm outline-none transition-colors",
"focus:bg-surface-secondary focus:text-content-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"data-[state=checked]:bg-surface-secondary data-[state=checked]:text-content-primary",
],
className,
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
{children}
<span className="absolute top-3.5 right-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<Circle className="h-2 w-2 fill-current" />
<Check className="h-4 w-4" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
));
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
+117 -157
View File
@@ -1,19 +1,24 @@
import { useTheme } from "@emotion/react";
import Divider from "@mui/material/Divider";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import Skeleton from "@mui/material/Skeleton";
import { visuallyHidden } from "@mui/utils";
import type * as TypesGen from "api/typesGenerated";
import { Abbr } from "components/Abbr/Abbr";
import { Button } from "components/Button/Button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "components/DropdownMenu/DropdownMenu";
import { displayError } from "components/GlobalSnackbar/utils";
import { Latency } from "components/Latency/Latency";
import type { ProxyContextValue } from "contexts/ProxyContext";
import { useAuthenticated } from "hooks";
import { ChevronDownIcon } from "lucide-react";
import { type FC, useRef, useState } from "react";
import { useNavigate } from "react-router";
import { type FC, useState } from "react";
import { Link } from "react-router";
import { sortProxiesByLatency } from "./proxyUtils";
interface ProxyMenuProps {
@@ -21,14 +26,11 @@ interface ProxyMenuProps {
}
export const ProxyMenu: FC<ProxyMenuProps> = ({ proxyContextValue }) => {
const theme = useTheme();
const buttonRef = useRef<HTMLButtonElement>(null);
const [isOpen, setIsOpen] = useState(false);
const [open, setOpen] = useState(false);
const [refetchDate, setRefetchDate] = useState<Date>();
const selectedProxy = proxyContextValue.proxy.proxy;
const refreshLatencies = proxyContextValue.refetchProxyLatencies;
const closeMenu = () => setIsOpen(false);
const navigate = useNavigate();
const closeMenu = () => setOpen(false);
const latencies = proxyContextValue.proxyLatencies;
const isLoadingLatencies = Object.keys(latencies).length === 0;
const isLoading = proxyContextValue.isLoading || isLoadingLatencies;
@@ -69,163 +71,121 @@ export const ProxyMenu: FC<ProxyMenuProps> = ({ proxyContextValue }) => {
}
return (
<>
<Button
variant="outline"
ref={buttonRef}
onClick={() => setIsOpen(true)}
size="lg"
>
<span css={{ ...visuallyHidden }}>
Latency for {selectedProxy?.display_name ?? "your region"}
</span>
<DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="lg">
<span css={{ ...visuallyHidden }}>
Latency for {selectedProxy?.display_name ?? "your region"}
</span>
{selectedProxy ? (
<>
<img
// Empty alt text used because we don't want to double up on
// screen reader announcements from visually-hidden span
alt=""
src={selectedProxy.icon_url}
/>
{selectedProxy ? (
<>
<img
// Empty alt text used because we don't want to double up on
// screen reader announcements from visually-hidden span
alt=""
src={selectedProxy.icon_url}
/>
<Latency
latency={latencies?.[selectedProxy.id]?.latencyMS}
isLoading={proxyLatencyLoading(selectedProxy)}
/>
</>
) : (
"Select Proxy"
)}
<ChevronDownIcon className="text-content-primary !size-icon-sm" />
</Button>
<Menu
open={isOpen}
anchorEl={buttonRef.current}
onClick={closeMenu}
onClose={closeMenu}
css={{ "& .MuiMenu-paper": { paddingTop: 8, paddingBottom: 8 } }}
// autoFocus here does not affect modal focus; it affects whether the
// first item in the list will get auto-focus when the menu opens. Have
// to turn this off because otherwise, screen readers will skip over all
// the descriptive text and will only have access to the latency options
autoFocus={false}
className="z-0"
>
{proxyContextValue.proxies &&
proxyContextValue.proxies.length > 1 && [
<div
key="description"
css={{
width: "100%",
maxWidth: "320px",
fontSize: 14,
padding: 16,
lineHeight: "140%",
}}
>
<h4
tabIndex={-1}
css={{
fontSize: "inherit",
fontWeight: 600,
lineHeight: "inherit",
margin: 0,
marginBottom: 4,
}}
>
Select a region nearest to you
</h4>
<p
css={{
fontSize: 13,
color: theme.palette.text.secondary,
lineHeight: "inherit",
marginTop: 0.5,
marginBottom: 0,
}}
>
Workspace proxies improve terminal and web app connections to
workspaces. This does not apply to{" "}
<Abbr title="Command-Line Interface" pronunciation="initialism">
CLI
</Abbr>{" "}
connections. A region must be manually selected, otherwise the
default primary region will be used.
</p>
</div>,
<Divider key="divider" />,
]}
{proxyContextValue.proxies &&
sortProxiesByLatency(proxyContextValue.proxies, latencies).map(
(proxy) => (
<MenuItem
key={proxy.id}
selected={proxy.id === selectedProxy?.id}
className="text-sm"
onClick={() => {
if (!proxy.healthy) {
displayError("Please select a healthy workspace proxy.");
closeMenu();
return;
}
proxyContextValue.setProxy(proxy);
closeMenu();
}}
>
<div className="flex gap-6 items-center w-full">
<div className="leading-[0] size-[14px]">
<img
src={proxy.icon_url}
alt=""
className="object-fit size-full"
/>
</div>
{proxy.display_name}
<Latency
className="ml-auto"
latency={latencies?.[proxy.id]?.latencyMS}
isLoading={proxyLatencyLoading(proxy)}
/>
</div>
</MenuItem>
),
<Latency
latency={latencies?.[selectedProxy.id]?.latencyMS}
isLoading={proxyLatencyLoading(selectedProxy)}
/>
</>
) : (
"Select Proxy"
)}
<Divider />
{Boolean(permissions.editWorkspaceProxies) && (
<MenuItem
css={{ fontSize: 14 }}
onClick={() => {
navigate("/deployment/workspace-proxies");
}}
<ChevronDownIcon className="text-content-primary !size-icon-lg" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-80">
{proxyContextValue.proxies && proxyContextValue.proxies.length > 1 && (
<DropdownMenuItem
disabled
className="flex flex-col gap-1 items-start data-[disabled]:opacity-100"
>
Proxy settings
</MenuItem>
<div className="text-content-primary font-semibold text-left">
Select a region nearest to you
</div>
<div className="text-xs text-content-secondary leading-relaxed">
Workspace proxies improve terminal and web app connections to
workspaces. This does not apply to{" "}
<Abbr title="Command-Line Interface" pronunciation="initialism">
CLI
</Abbr>{" "}
connections. A region must be manually selected, otherwise the
default primary region will be used.
</div>
</DropdownMenuItem>
)}
<MenuItem
css={{ fontSize: 14 }}
{proxyContextValue.proxies && proxyContextValue.proxies.length > 1 && (
<DropdownMenuSeparator />
)}
{proxyContextValue.proxies && (
<DropdownMenuRadioGroup value={selectedProxy?.id}>
{sortProxiesByLatency(proxyContextValue.proxies, latencies).map(
(proxy) => (
<DropdownMenuRadioItem
value={proxy.id}
key={proxy.id}
onClick={(e) => {
e.preventDefault();
if (!proxy.healthy) {
displayError("Please select a healthy workspace proxy.");
closeMenu();
return;
}
proxyContextValue.setProxy(proxy);
closeMenu();
}}
>
<div className="flex gap-3 items-center w-full">
<div className="leading-none size-4">
<img
src={proxy.icon_url}
alt=""
className="object-contain size-full"
/>
</div>
{proxy.display_name}
<Latency
className="ml-auto"
latency={latencies?.[proxy.id]?.latencyMS}
isLoading={proxyLatencyLoading(proxy)}
/>
</div>
</DropdownMenuRadioItem>
),
)}
</DropdownMenuRadioGroup>
)}
<DropdownMenuSeparator />
{Boolean(permissions.editWorkspaceProxies) && (
<DropdownMenuItem asChild>
<Link to="/deployment/workspace-proxies">
<span>Proxy settings</span>
</Link>
</DropdownMenuItem>
)}
<DropdownMenuItem
onClick={(e) => {
// Stop the menu from closing
e.stopPropagation();
// Refresh the latencies.
e.preventDefault();
const refetchDate = refreshLatencies();
setRefetchDate(refetchDate);
}}
>
Refresh Latencies
</MenuItem>
</Menu>
</>
Refresh latencies
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};