Skip to content

Commit 50e5a89

Browse files
committed
feat(site): add latency to the terminal
1 parent 004ad17 commit 50e5a89

File tree

7 files changed

+157
-61
lines changed

7 files changed

+157
-61
lines changed

site/src/components/Navbar/NavbarView.tsx

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Drawer from "@mui/material/Drawer"
22
import IconButton from "@mui/material/IconButton"
33
import List from "@mui/material/List"
44
import ListItem from "@mui/material/ListItem"
5-
import { makeStyles, useTheme } from "@mui/styles"
5+
import { makeStyles } from "@mui/styles"
66
import MenuIcon from "@mui/icons-material/Menu"
77
import { CoderIcon } from "components/Icons/CoderIcon"
88
import { FC, useRef, useState } from "react"
@@ -20,10 +20,9 @@ import KeyboardArrowDownOutlined from "@mui/icons-material/KeyboardArrowDownOutl
2020
import { ProxyContextValue } from "contexts/ProxyContext"
2121
import { displayError } from "components/GlobalSnackbar/utils"
2222
import Divider from "@mui/material/Divider"
23-
import HelpOutline from "@mui/icons-material/HelpOutline"
24-
import Tooltip from "@mui/material/Tooltip"
2523
import Skeleton from "@mui/material/Skeleton"
2624
import { BUTTON_SM_HEIGHT } from "theme/theme"
25+
import { ProxyStatusLatency } from "components/ProxyStatusLatency/ProxyStatusLatency"
2726

2827
export const USERS_LINK = `/users?filter=${encodeURIComponent("status:active")}`
2928

@@ -232,7 +231,6 @@ const ProxyMenu: FC<{ proxyContextValue: ProxyContextValue }> = ({
232231
</Box>
233232
{selectedProxy.display_name}
234233
<ProxyStatusLatency
235-
proxy={selectedProxy}
236234
latency={latencies?.[selectedProxy.id]?.latencyMS}
237235
/>
238236
</Box>
@@ -277,10 +275,7 @@ const ProxyMenu: FC<{ proxyContextValue: ProxyContextValue }> = ({
277275
/>
278276
</Box>
279277
{proxy.display_name}
280-
<ProxyStatusLatency
281-
proxy={proxy}
282-
latency={latencies?.[proxy.id]?.latencyMS}
283-
/>
278+
<ProxyStatusLatency latency={latencies?.[proxy.id]?.latencyMS} />
284279
</Box>
285280
</MenuItem>
286281
))}
@@ -301,42 +296,6 @@ const ProxyMenu: FC<{ proxyContextValue: ProxyContextValue }> = ({
301296
)
302297
}
303298

304-
const ProxyStatusLatency: FC<{ proxy: TypesGen.Region; latency?: number }> = ({
305-
proxy,
306-
latency,
307-
}) => {
308-
const theme = useTheme()
309-
let color = theme.palette.success.light
310-
311-
if (!latency) {
312-
return (
313-
<Tooltip title="Latency not available">
314-
<HelpOutline
315-
sx={{
316-
ml: "auto",
317-
fontSize: "14px !important",
318-
color: (theme) => theme.palette.text.secondary,
319-
}}
320-
/>
321-
</Tooltip>
322-
)
323-
}
324-
325-
if (latency >= 300) {
326-
color = theme.palette.error.light
327-
}
328-
329-
if (!proxy.healthy || latency >= 100) {
330-
color = theme.palette.warning.light
331-
}
332-
333-
return (
334-
<Box sx={{ color, fontSize: 13, marginLeft: "auto" }}>
335-
{latency.toFixed(0)}ms
336-
</Box>
337-
)
338-
}
339-
340299
const useStyles = makeStyles((theme) => ({
341300
root: {
342301
height: navHeight,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useTheme } from "@mui/material/styles"
2+
import HelpOutline from "@mui/icons-material/HelpOutline"
3+
import Box from "@mui/material/Box"
4+
import Tooltip from "@mui/material/Tooltip"
5+
import { FC } from "react"
6+
import { getLatencyColor } from "utils/latency"
7+
8+
export const ProxyStatusLatency: FC<{ latency?: number }> = ({ latency }) => {
9+
const theme = useTheme()
10+
const color = getLatencyColor(theme, latency)
11+
12+
if (!latency) {
13+
return (
14+
<Tooltip title="Latency not available">
15+
<HelpOutline
16+
sx={{
17+
ml: "auto",
18+
fontSize: "14px !important",
19+
color,
20+
}}
21+
/>
22+
</Tooltip>
23+
)
24+
}
25+
26+
return (
27+
<Box sx={{ color, fontSize: 13, marginLeft: "auto" }}>
28+
{latency.toFixed(0)}ms
29+
</Box>
30+
)
31+
}

site/src/components/Resources/AgentLatency.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
} from "components/Tooltips/HelpTooltip"
99
import { Stack } from "components/Stack/Stack"
1010
import { WorkspaceAgent, DERPRegion } from "api/typesGenerated"
11-
import { getLatencyColor } from "utils/colors"
11+
import { getLatencyColor } from "utils/latency"
1212

1313
const getDisplayLatency = (theme: Theme, agent: WorkspaceAgent) => {
1414
// Find the right latency to display

site/src/pages/TerminalPage/TerminalPage.tsx

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Button from "@mui/material/Button"
2-
import { makeStyles } from "@mui/styles"
2+
import { makeStyles, useTheme } from "@mui/styles"
33
import WarningIcon from "@mui/icons-material/ErrorOutlineRounded"
44
import RefreshOutlined from "@mui/icons-material/RefreshOutlined"
55
import { useMachine } from "@xstate/react"
@@ -20,6 +20,12 @@ import { terminalMachine } from "../../xServices/terminal/terminalXService"
2020
import { useProxy } from "contexts/ProxyContext"
2121
import { combineClasses } from "utils/combineClasses"
2222
import Box from "@mui/material/Box"
23+
import { useDashboard } from "components/Dashboard/DashboardProvider"
24+
import { Region } from "api/typesGenerated"
25+
import { getLatencyColor } from "utils/latency"
26+
import Popover from "@mui/material/Popover"
27+
import { ProxyStatusLatency } from "components/ProxyStatusLatency/ProxyStatusLatency"
28+
import { alpha } from "@mui/material"
2329

2430
export const Language = {
2531
workspaceErrorMessagePrefix: "Unable to fetch workspace: ",
@@ -85,6 +91,12 @@ const TerminalPage: FC<
8591
const shouldDisplayStartupError = workspaceAgent
8692
? workspaceAgent.lifecycle_state === "start_error"
8793
: false
94+
const dashboard = useDashboard()
95+
const proxyContext = useProxy()
96+
const selectedProxy = proxyContext.proxy.proxy
97+
const latency = selectedProxy
98+
? proxyContext.proxyLatencies[selectedProxy.id]
99+
: undefined
88100

89101
// handleWebLink handles opening of URLs in the terminal!
90102
const handleWebLink = useCallback(
@@ -347,11 +359,103 @@ const TerminalPage: FC<
347359
ref={xtermRef}
348360
data-testid="terminal"
349361
/>
362+
{dashboard.experiments.includes("moons") &&
363+
selectedProxy &&
364+
latency && (
365+
<Latency proxy={selectedProxy} latency={latency.latencyMS} />
366+
)}
350367
</Box>
351368
</>
352369
)
353370
}
354371

372+
const Latency = ({ proxy, latency }: { proxy: Region; latency?: number }) => {
373+
const theme = useTheme()
374+
const color = getLatencyColor(theme, latency)
375+
const anchorRef = useRef<HTMLButtonElement>(null)
376+
const [isOpen, setIsOpen] = useState(false)
377+
378+
return (
379+
<Box sx={{ position: "fixed", bottom: 24, right: 24, zIndex: 10 }}>
380+
<Box
381+
ref={anchorRef}
382+
component="button"
383+
aria-label="Terminal latency"
384+
aria-haspopup="true"
385+
onMouseEnter={() => setIsOpen(true)}
386+
onMouseLeave={() => setIsOpen(false)}
387+
sx={{
388+
padding: 0.75,
389+
border: `1px solid ${alpha(color, 0.5)}`,
390+
borderRadius: 9999,
391+
background: "none",
392+
cursor: "pointer",
393+
}}
394+
>
395+
<Box
396+
sx={{
397+
height: 8,
398+
width: 8,
399+
backgroundColor: color,
400+
border: 0,
401+
borderRadius: 9999,
402+
}}
403+
/>
404+
</Box>
405+
<Popover
406+
id="latency-popover"
407+
disableRestoreFocus
408+
anchorEl={anchorRef.current}
409+
open={isOpen}
410+
onClose={() => setIsOpen(false)}
411+
sx={{
412+
pointerEvents: "none",
413+
"& .MuiPaper-root": {
414+
padding: (theme) => theme.spacing(1, 2),
415+
marginTop: -1,
416+
},
417+
}}
418+
anchorOrigin={{
419+
vertical: "top",
420+
horizontal: "right",
421+
}}
422+
transformOrigin={{
423+
vertical: "bottom",
424+
horizontal: "right",
425+
}}
426+
>
427+
<Box
428+
sx={{
429+
fontSize: 13,
430+
color: (theme) => theme.palette.text.secondary,
431+
fontWeight: 500,
432+
}}
433+
>
434+
Selected proxy
435+
</Box>
436+
<Box
437+
sx={{ fontSize: 14, display: "flex", gap: 3, alignItems: "center" }}
438+
>
439+
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
440+
<Box width={12} height={12} lineHeight={0}>
441+
<Box
442+
component="img"
443+
src={proxy.icon_url}
444+
alt=""
445+
sx={{ objectFit: "contain" }}
446+
width="100%"
447+
height="100%"
448+
/>
449+
</Box>
450+
{proxy.display_name}
451+
</Box>
452+
<ProxyStatusLatency latency={latency} />
453+
</Box>
454+
</Popover>
455+
</Box>
456+
)
457+
}
458+
355459
const useReloading = (isDisconnected: boolean) => {
356460
const [status, setStatus] = useState<"reloading" | "notReloading">(
357461
"notReloading",

site/src/pages/UserSettingsPage/WorkspaceProxyPage/WorkspaceProxyRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { makeStyles } from "@mui/styles"
1313
import { combineClasses } from "utils/combineClasses"
1414
import { ProxyLatencyReport } from "contexts/useProxyLatency"
15-
import { getLatencyColor } from "utils/colors"
15+
import { getLatencyColor } from "utils/latency"
1616
import { alpha } from "@mui/material/styles"
1717

1818
export const ProxyRow: FC<{

site/src/utils/colors.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { Theme } from "@mui/material/styles"
2-
31
// Used to convert our theme colors to Hex since monaco theme only support hex colors
42
// From https://www.jameslmilner.com/posts/converting-rgb-hex-hsl-colors/
53
export function hslToHex(hsl: string): string {
@@ -23,15 +21,3 @@ export function hslToHex(hsl: string): string {
2321
}
2422
return `#${f(0)}${f(8)}${f(4)}`
2523
}
26-
27-
// getLatencyColor is the text color to use for a given latency
28-
// in milliseconds.
29-
export const getLatencyColor = (theme: Theme, latency: number) => {
30-
let color = theme.palette.success.light
31-
if (latency >= 150 && latency < 300) {
32-
color = theme.palette.warning.light
33-
} else if (latency >= 300) {
34-
color = theme.palette.error.light
35-
}
36-
return color
37-
}

site/src/utils/latency.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Theme } from "@mui/material/styles"
2+
3+
export const getLatencyColor = (theme: Theme, latency?: number) => {
4+
if (!latency) {
5+
return theme.palette.text.secondary
6+
}
7+
8+
let color = theme.palette.success.light
9+
10+
if (latency >= 150 && latency < 300) {
11+
color = theme.palette.warning.light
12+
} else if (latency >= 300) {
13+
color = theme.palette.error.light
14+
}
15+
return color
16+
}

0 commit comments

Comments
 (0)