Skip to content

Commit e721eec

Browse files
committed
wip: Update resources table
1 parent 443173c commit e721eec

File tree

10 files changed

+774
-30
lines changed

10 files changed

+774
-30
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { useRef, useState, FC } from "react"
2+
import { makeStyles, Theme, useTheme } from "@material-ui/core/styles"
3+
import {
4+
HelpTooltipText,
5+
HelpPopover,
6+
HelpTooltipTitle,
7+
} from "components/Tooltips/HelpTooltip"
8+
import { Stack } from "components/Stack/Stack"
9+
import { WorkspaceAgent, DERPRegion } from "api/typesGenerated"
10+
11+
const getDisplayLatency = (theme: Theme, agent: WorkspaceAgent) => {
12+
// Find the right latency to display
13+
const latencyValues = Object.values(agent.latency ?? {})
14+
const latency =
15+
latencyValues.find((derp) => derp.preferred) ??
16+
// Accessing an array index can return undefined as well
17+
// for some reason TS does not handle that
18+
(latencyValues[0] as DERPRegion | undefined)
19+
20+
if (!latency) {
21+
return undefined
22+
}
23+
24+
// Get the color
25+
let color = theme.palette.success.light
26+
if (latency.latency_ms >= 150 && latency.latency_ms < 300) {
27+
color = theme.palette.warning.light
28+
} else if (latency.latency_ms >= 300) {
29+
color = theme.palette.error.light
30+
}
31+
32+
return {
33+
...latency,
34+
color,
35+
}
36+
}
37+
38+
export const AgentLatency: FC<{ agent: WorkspaceAgent }> = ({ agent }) => {
39+
const theme: Theme = useTheme()
40+
const anchorRef = useRef<HTMLButtonElement>(null)
41+
const [isOpen, setIsOpen] = useState(false)
42+
const id = isOpen ? "latency-popover" : undefined
43+
const latency = getDisplayLatency(theme, agent)
44+
const styles = useStyles()
45+
46+
if (!latency || !agent.latency) {
47+
return null
48+
}
49+
50+
return (
51+
<>
52+
<span
53+
role="presentation"
54+
aria-label="latency"
55+
ref={anchorRef}
56+
onMouseEnter={() => setIsOpen(true)}
57+
className={styles.trigger}
58+
style={{ color: latency.color }}
59+
>
60+
{Math.round(Math.round(latency.latency_ms))}ms
61+
</span>
62+
<HelpPopover
63+
id={id}
64+
open={isOpen}
65+
anchorEl={anchorRef.current}
66+
onOpen={() => setIsOpen(true)}
67+
onClose={() => setIsOpen(false)}
68+
>
69+
<HelpTooltipTitle>Latency</HelpTooltipTitle>
70+
<HelpTooltipText>
71+
Latency from relay servers, used when connections cannot connect
72+
peer-to-peer. Star indicates the preferred relay.
73+
</HelpTooltipText>
74+
75+
<HelpTooltipText>
76+
<Stack direction="column" spacing={1} className={styles.regions}>
77+
{Object.keys(agent.latency).map((regionName) => {
78+
if (!agent.latency) {
79+
throw new Error("No latency found on agent")
80+
}
81+
82+
const region = agent.latency[regionName]
83+
84+
return (
85+
<Stack
86+
direction="row"
87+
key={regionName}
88+
spacing={0.5}
89+
justifyContent="space-between"
90+
className={region.preferred ? styles.preferred : undefined}
91+
>
92+
<strong>{regionName}</strong>
93+
{Math.round(region.latency_ms)}ms
94+
</Stack>
95+
)
96+
})}
97+
</Stack>
98+
</HelpTooltipText>
99+
</HelpPopover>
100+
</>
101+
)
102+
}
103+
104+
const useStyles = makeStyles((theme) => ({
105+
trigger: {
106+
cursor: "pointer",
107+
},
108+
regions: {
109+
marginTop: theme.spacing(2),
110+
},
111+
preferred: {
112+
color: theme.palette.text.primary,
113+
},
114+
}))
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { useRef, useState, FC } from "react"
2+
import { makeStyles } from "@material-ui/core/styles"
3+
import {
4+
HelpTooltipText,
5+
HelpPopover,
6+
HelpTooltipTitle,
7+
} from "components/Tooltips/HelpTooltip"
8+
import { WorkspaceAgent } from "api/typesGenerated"
9+
import { getDisplayVersionStatus } from "util/workspace"
10+
11+
export const AgentVersion: FC<{
12+
agent: WorkspaceAgent
13+
serverVersion: string
14+
}> = ({ agent, serverVersion }) => {
15+
const styles = useStyles()
16+
const anchorRef = useRef<HTMLButtonElement>(null)
17+
const [isOpen, setIsOpen] = useState(false)
18+
const id = isOpen ? "version-outdated-popover" : undefined
19+
const { displayVersion, outdated } = getDisplayVersionStatus(
20+
agent.version,
21+
serverVersion,
22+
)
23+
24+
if (!outdated) {
25+
return <span>{displayVersion}</span>
26+
}
27+
28+
return (
29+
<>
30+
<span
31+
role="presentation"
32+
aria-label="latency"
33+
ref={anchorRef}
34+
onMouseEnter={() => setIsOpen(true)}
35+
className={styles.trigger}
36+
>
37+
{displayVersion}
38+
</span>
39+
<HelpPopover
40+
id={id}
41+
open={isOpen}
42+
anchorEl={anchorRef.current}
43+
onOpen={() => setIsOpen(true)}
44+
onClose={() => setIsOpen(false)}
45+
>
46+
<HelpTooltipTitle>Agent Outdated</HelpTooltipTitle>
47+
<HelpTooltipText>
48+
This agent is an older version than the Coder server. This can happen
49+
after you update Coder with running workspaces. To fix this, you can
50+
stop and start the workspace.
51+
</HelpTooltipText>
52+
</HelpPopover>
53+
</>
54+
)
55+
}
56+
57+
const useStyles = makeStyles((theme) => ({
58+
trigger: {
59+
cursor: "pointer",
60+
color: theme.palette.warning.light,
61+
},
62+
}))
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Story } from "@storybook/react"
2+
import {
3+
MockWorkspace,
4+
MockWorkspaceAgent,
5+
MockWorkspaceResource,
6+
} from "testHelpers/entities"
7+
import { ResourceCard, ResourceCardProps } from "./ResourceCard"
8+
9+
export default {
10+
title: "components/ResourceCard",
11+
component: ResourceCard,
12+
}
13+
14+
const Template: Story<ResourceCardProps> = (args) => <ResourceCard {...args} />
15+
16+
export const Example = Template.bind({})
17+
Example.args = {
18+
resource: MockWorkspaceResource,
19+
workspace: MockWorkspace,
20+
applicationsHost: "https://dev.coder.com",
21+
hideSSHButton: false,
22+
showApps: true,
23+
serverVersion: MockWorkspaceAgent.version,
24+
}
25+
26+
export const NotShowingApps = Template.bind({})
27+
NotShowingApps.args = {
28+
...Example.args,
29+
showApps: false,
30+
}
31+
32+
export const HideSSHButton = Template.bind({})
33+
HideSSHButton.args = {
34+
...Example.args,
35+
hideSSHButton: true,
36+
}
37+
38+
export const BunchOfMetadata = Template.bind({})
39+
BunchOfMetadata.args = {
40+
...Example.args,
41+
resource: {
42+
...MockWorkspaceResource,
43+
metadata: [
44+
{ key: "type", value: "kubernetes_pod", sensitive: false },
45+
{
46+
key: "CPU(limits, requests)",
47+
value: "2 cores, 500m",
48+
sensitive: false,
49+
},
50+
{ key: "container image pull policy", value: "Always", sensitive: false },
51+
{ key: "Disk", value: "10GiB", sensitive: false },
52+
{
53+
key: "image",
54+
value: "docker.io/markmilligan/pycharm-community:latest",
55+
sensitive: false,
56+
},
57+
{ key: "kubernetes namespace", value: "oss", sensitive: false },
58+
{
59+
key: "memory(limits, requests)",
60+
value: "4GB, 500mi",
61+
sensitive: false,
62+
},
63+
{
64+
key: "security context - container",
65+
value: "run_as_user 1000",
66+
sensitive: false,
67+
},
68+
{
69+
key: "security context - pod",
70+
value: "run_as_user 1000 fs_group 1000",
71+
sensitive: false,
72+
},
73+
{ key: "volume", value: "/home/coder", sensitive: false },
74+
],
75+
},
76+
}

0 commit comments

Comments
 (0)