Skip to content

Commit 690ba66

Browse files
feat: Add metadata support to the UI (coder#3431)
1 parent 53400c6 commit 690ba66

File tree

3 files changed

+127
-10
lines changed

3 files changed

+127
-10
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import IconButton from "@material-ui/core/IconButton"
2+
import { makeStyles } from "@material-ui/core/styles"
3+
import Tooltip from "@material-ui/core/Tooltip"
4+
import VisibilityOffOutlined from "@material-ui/icons/VisibilityOffOutlined"
5+
import VisibilityOutlined from "@material-ui/icons/VisibilityOutlined"
6+
import { WorkspaceResource } from "api/typesGenerated"
7+
import { FC, useState } from "react"
8+
import { TableCellData, TableCellDataPrimary } from "../TableCellData/TableCellData"
9+
import { ResourceAvatar } from "./ResourceAvatar"
10+
11+
const Language = {
12+
showLabel: "Show value",
13+
hideLabel: "Hide value",
14+
}
15+
16+
const SensitiveValue: React.FC<{ value: string }> = ({ value }) => {
17+
const [shouldDisplay, setShouldDisplay] = useState(false)
18+
const styles = useStyles()
19+
const displayValue = shouldDisplay ? value : "••••••••"
20+
const buttonLabel = shouldDisplay ? Language.hideLabel : Language.showLabel
21+
const icon = shouldDisplay ? <VisibilityOffOutlined /> : <VisibilityOutlined />
22+
23+
return (
24+
<div className={styles.sensitiveValue}>
25+
{displayValue}
26+
<Tooltip title={buttonLabel}>
27+
<IconButton
28+
className={styles.button}
29+
onClick={() => {
30+
setShouldDisplay((value) => !value)
31+
}}
32+
size="small"
33+
aria-label={buttonLabel}
34+
>
35+
{icon}
36+
</IconButton>
37+
</Tooltip>
38+
</div>
39+
)
40+
}
41+
42+
export interface ResourceAvatarDataProps {
43+
resource: WorkspaceResource
44+
}
45+
46+
export const ResourceAvatarData: FC<ResourceAvatarDataProps> = ({ resource }) => {
47+
const styles = useStyles()
48+
49+
return (
50+
<div className={styles.root}>
51+
<div className={styles.avatarWrapper}>
52+
<ResourceAvatar type={resource.type} />
53+
</div>
54+
55+
<TableCellData>
56+
<TableCellDataPrimary highlight>{resource.name}</TableCellDataPrimary>
57+
<div className={styles.data}>
58+
{resource.metadata?.map((metadata) => (
59+
<div key={metadata.key} className={styles.dataRow}>
60+
<strong>{metadata.key}:</strong>
61+
{metadata.sensitive ? (
62+
<SensitiveValue value={metadata.value} />
63+
) : (
64+
<div>{metadata.value}</div>
65+
)}
66+
</div>
67+
))}
68+
</div>
69+
</TableCellData>
70+
</div>
71+
)
72+
}
73+
74+
const useStyles = makeStyles((theme) => ({
75+
root: {
76+
display: "flex",
77+
},
78+
79+
avatarWrapper: {
80+
marginRight: theme.spacing(3),
81+
paddingTop: theme.spacing(0.5),
82+
},
83+
84+
data: {
85+
color: theme.palette.text.secondary,
86+
fontSize: 14,
87+
marginTop: theme.spacing(0.75),
88+
display: "grid",
89+
gridAutoFlow: "row",
90+
whiteSpace: "nowrap",
91+
gap: theme.spacing(0.75),
92+
},
93+
94+
dataRow: {
95+
display: "flex",
96+
alignItems: "center",
97+
98+
"& strong": {
99+
marginRight: theme.spacing(1),
100+
},
101+
},
102+
103+
sensitiveValue: {
104+
display: "flex",
105+
alignItems: "center",
106+
},
107+
108+
button: {
109+
marginLeft: theme.spacing(0.5),
110+
color: "inherit",
111+
112+
"& .MuiSvgIcon-root": {
113+
width: 16,
114+
height: 16,
115+
},
116+
},
117+
}))

site/src/components/Resources/Resources.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import useTheme from "@material-ui/styles/useTheme"
99
import { ErrorSummary } from "components/ErrorSummary/ErrorSummary"
1010
import { FC } from "react"
1111
import { Workspace, WorkspaceResource } from "../../api/typesGenerated"
12-
import { AvatarData } from "../../components/AvatarData/AvatarData"
1312
import { getDisplayAgentStatus } from "../../util/workspace"
1413
import { AppLink } from "../AppLink/AppLink"
1514
import { SSHButton } from "../SSHButton/SSHButton"
@@ -18,7 +17,7 @@ import { TableHeaderRow } from "../TableHeaders/TableHeaders"
1817
import { TerminalLink } from "../TerminalLink/TerminalLink"
1918
import { AgentHelpTooltip } from "../Tooltips/AgentHelpTooltip"
2019
import { ResourcesHelpTooltip } from "../Tooltips/ResourcesHelpTooltip"
21-
import { ResourceAvatar } from "./ResourceAvatar"
20+
import { ResourceAvatarData } from "./ResourceAvatarData"
2221

2322
const Language = {
2423
resources: "Resources",
@@ -73,14 +72,7 @@ export const Resources: FC<ResourcesProps> = ({
7372
/* We need to initialize the agents to display the resource */
7473
}
7574
const agents = resource.agents ?? [null]
76-
const resourceName = (
77-
<AvatarData
78-
avatar={<ResourceAvatar type={resource.type} />}
79-
title={resource.name}
80-
subtitle={resource.type}
81-
highlightTitle
82-
/>
83-
)
75+
const resourceName = <ResourceAvatarData resource={resource} />
8476

8577
return agents.map((agent, agentIndex) => {
8678
{

site/src/testHelpers/entities.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,20 @@ export const MockWorkspaceResource: TypesGen.WorkspaceResource = {
287287
name: "a-workspace-resource",
288288
type: "google_compute_disk",
289289
workspace_transition: "start",
290+
metadata: [
291+
{ key: "type", value: "a-workspace-resource", sensitive: false },
292+
{ key: "api_key", value: "12345678", sensitive: true },
293+
],
290294
}
291295

292296
export const MockWorkspaceResource2 = {
293297
...MockWorkspaceResource,
294298
id: "test-workspace-resource-2",
295299
name: "another-workspace-resource",
300+
metadata: [
301+
{ key: "type", value: "google_compute_disk", sensitive: false },
302+
{ key: "size", value: "32GB", sensitive: false },
303+
],
296304
}
297305

298306
export const MockUserAgent: Types.UserAgent = {

0 commit comments

Comments
 (0)