Skip to content

Commit 1f63a11

Browse files
refactor(site): refactor resource and agents (#11647)
1 parent 89fd294 commit 1f63a11

18 files changed

+600
-367
lines changed

site/src/components/Resources/AgentButton.tsx

+10-14
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,28 @@
11
import Button, { type ButtonProps } from "@mui/material/Button";
2-
import { useTheme } from "@emotion/react";
32
import { forwardRef } from "react";
43

54
// eslint-disable-next-line react/display-name -- Name is inferred from variable name
65
export const AgentButton = forwardRef<HTMLButtonElement, ButtonProps>(
76
(props, ref) => {
87
const { children, ...buttonProps } = props;
9-
const theme = useTheme();
108

119
return (
1210
<Button
13-
color="neutral"
1411
{...buttonProps}
12+
color="neutral"
13+
size="xlarge"
14+
variant="contained"
1515
ref={ref}
16-
css={{
17-
backgroundColor: theme.palette.background.default,
18-
19-
"&:hover": {
20-
backgroundColor: theme.palette.background.paper,
21-
},
22-
16+
css={(theme) => ({
17+
padding: "12px 20px",
18+
color: theme.palette.text.primary,
2319
// Making them smaller since those icons don't have a padding around them
24-
"& .MuiButton-startIcon": {
25-
width: 12,
26-
height: 12,
20+
"& .MuiButton-startIcon, & .MuiButton-endIcon": {
21+
width: 16,
22+
height: 16,
2723
"& svg": { width: "100%", height: "100%" },
2824
},
29-
}}
25+
})}
3026
>
3127
{children}
3228
</Button>

site/src/components/Resources/AgentMetadata.tsx

+83-96
Original file line numberDiff line numberDiff line change
@@ -24,71 +24,6 @@ type ItemStatus = "stale" | "valid" | "loading";
2424

2525
export const WatchAgentMetadataContext = createContext(watchAgentMetadata);
2626

27-
interface MetadataItemProps {
28-
item: WorkspaceAgentMetadata;
29-
}
30-
31-
const MetadataItem: FC<MetadataItemProps> = ({ item }) => {
32-
if (item.result === undefined) {
33-
throw new Error("Metadata item result is undefined");
34-
}
35-
if (item.description === undefined) {
36-
throw new Error("Metadata item description is undefined");
37-
}
38-
39-
const staleThreshold = Math.max(
40-
item.description.interval + item.description.timeout * 2,
41-
// In case there is intense backpressure, we give a little bit of slack.
42-
5,
43-
);
44-
45-
const status: ItemStatus = (() => {
46-
const year = dayjs(item.result.collected_at).year();
47-
if (year <= 1970 || isNaN(year)) {
48-
return "loading";
49-
}
50-
// There is a special circumstance for metadata with `interval: 0`. It is
51-
// expected that they run once and never again, so never display them as
52-
// stale.
53-
if (item.result.age > staleThreshold && item.description.interval > 0) {
54-
return "stale";
55-
}
56-
return "valid";
57-
})();
58-
59-
// Stale data is as good as no data. Plus, we want to build confidence in our
60-
// users that what's shown is real. If times aren't correctly synced this
61-
// could be buggy. But, how common is that anyways?
62-
const value =
63-
status === "loading" ? (
64-
<Skeleton width={65} height={12} variant="text" css={styles.skeleton} />
65-
) : status === "stale" ? (
66-
<Tooltip title="This data is stale and no longer up to date">
67-
<StaticWidth css={[styles.metadataValue, styles.metadataStale]}>
68-
{item.result.value}
69-
</StaticWidth>
70-
</Tooltip>
71-
) : (
72-
<StaticWidth
73-
css={[
74-
styles.metadataValue,
75-
item.result.error.length === 0
76-
? styles.metadataValueSuccess
77-
: styles.metadataValueError,
78-
]}
79-
>
80-
{item.result.value}
81-
</StaticWidth>
82-
);
83-
84-
return (
85-
<div css={styles.metadata}>
86-
<div css={styles.metadataLabel}>{item.description.display_name}</div>
87-
<div>{value}</div>
88-
</div>
89-
);
90-
};
91-
9227
export interface AgentMetadataViewProps {
9328
metadata: WorkspaceAgentMetadata[];
9429
}
@@ -98,16 +33,11 @@ export const AgentMetadataView: FC<AgentMetadataViewProps> = ({ metadata }) => {
9833
return null;
9934
}
10035
return (
101-
<div css={styles.root}>
102-
<Stack alignItems="baseline" direction="row" spacing={6}>
103-
{metadata.map((m) => {
104-
if (m.description === undefined) {
105-
throw new Error("Metadata item description is undefined");
106-
}
107-
return <MetadataItem key={m.description.key} item={m} />;
108-
})}
109-
</Stack>
110-
</div>
36+
<section css={styles.root}>
37+
{metadata.map((m) => (
38+
<MetadataItem key={m.description.key} item={m} />
39+
))}
40+
</section>
11141
);
11242
};
11343

@@ -162,13 +92,19 @@ export const AgentMetadata: FC<AgentMetadataProps> = ({
16292

16393
if (metadata === undefined) {
16494
return (
165-
<div css={styles.root}>
95+
<section css={styles.root}>
16696
<AgentMetadataSkeleton />
167-
</div>
97+
</section>
16898
);
16999
}
170100

171-
return <AgentMetadataView metadata={metadata} />;
101+
return (
102+
<AgentMetadataView
103+
metadata={[...metadata].sort((a, b) =>
104+
a.description.display_name.localeCompare(b.description.display_name),
105+
)}
106+
/>
107+
);
172108
};
173109

174110
export const AgentMetadataSkeleton: FC = () => {
@@ -192,6 +128,64 @@ export const AgentMetadataSkeleton: FC = () => {
192128
);
193129
};
194130

131+
interface MetadataItemProps {
132+
item: WorkspaceAgentMetadata;
133+
}
134+
135+
const MetadataItem: FC<MetadataItemProps> = ({ item }) => {
136+
const staleThreshold = Math.max(
137+
item.description.interval + item.description.timeout * 2,
138+
// In case there is intense backpressure, we give a little bit of slack.
139+
5,
140+
);
141+
142+
const status: ItemStatus = (() => {
143+
const year = dayjs(item.result.collected_at).year();
144+
if (year <= 1970 || isNaN(year)) {
145+
return "loading";
146+
}
147+
// There is a special circumstance for metadata with `interval: 0`. It is
148+
// expected that they run once and never again, so never display them as
149+
// stale.
150+
if (item.result.age > staleThreshold && item.description.interval > 0) {
151+
return "stale";
152+
}
153+
return "valid";
154+
})();
155+
156+
// Stale data is as good as no data. Plus, we want to build confidence in our
157+
// users that what's shown is real. If times aren't correctly synced this
158+
// could be buggy. But, how common is that anyways?
159+
const value =
160+
status === "loading" ? (
161+
<Skeleton width={65} height={12} variant="text" css={styles.skeleton} />
162+
) : status === "stale" ? (
163+
<Tooltip title="This data is stale and no longer up to date">
164+
<StaticWidth css={[styles.metadataValue, styles.metadataStale]}>
165+
{item.result.value}
166+
</StaticWidth>
167+
</Tooltip>
168+
) : (
169+
<StaticWidth
170+
css={[
171+
styles.metadataValue,
172+
item.result.error.length === 0
173+
? styles.metadataValueSuccess
174+
: styles.metadataValueError,
175+
]}
176+
>
177+
{item.result.value}
178+
</StaticWidth>
179+
);
180+
181+
return (
182+
<div css={styles.metadata}>
183+
<div css={styles.metadataLabel}>{item.description.display_name}</div>
184+
<div>{value}</div>
185+
</div>
186+
);
187+
};
188+
195189
const StaticWidth: FC<HTMLAttributes<HTMLDivElement>> = ({
196190
children,
197191
...attrs
@@ -221,33 +215,28 @@ const StaticWidth: FC<HTMLAttributes<HTMLDivElement>> = ({
221215
// These are more or less copied from
222216
// site/src/components/Resources/ResourceCard.tsx
223217
const styles = {
224-
root: (theme) => ({
225-
padding: "20px 32px",
226-
borderTop: `1px solid ${theme.palette.divider}`,
227-
overflowX: "auto",
228-
scrollPadding: "0 32px",
229-
}),
218+
root: {
219+
display: "flex",
220+
alignItems: "baseline",
221+
flexWrap: "wrap",
222+
gap: 32,
223+
rowGap: 16,
224+
},
230225

231226
metadata: {
232-
fontSize: 12,
233-
lineHeight: "normal",
227+
lineHeight: "1.6",
234228
display: "flex",
235229
flexDirection: "column",
236-
gap: 4,
237230
overflow: "visible",
238-
239-
// Because of scrolling
240-
"&:last-child": {
241-
paddingRight: 32,
242-
},
231+
flexShrink: 0,
243232
},
244233

245234
metadataLabel: (theme) => ({
246235
color: theme.palette.text.secondary,
247236
textOverflow: "ellipsis",
248237
overflow: "hidden",
249238
whiteSpace: "nowrap",
250-
fontWeight: 500,
239+
fontSize: 13,
251240
}),
252241

253242
metadataValue: {
@@ -259,9 +248,7 @@ const styles = {
259248
},
260249

261250
metadataValueSuccess: (theme) => ({
262-
// color: theme.palette.success.light,
263-
color: theme.experimental.roles.success.fill,
264-
// color: theme.experimental.roles.success.text,
251+
color: theme.experimental.roles.success.outline,
265252
}),
266253

267254
metadataValueError: (theme) => ({

site/src/components/Resources/AgentRow.stories.tsx

+10-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
MockWorkspaceAgentDeprecated,
2121
MockWorkspaceApp,
2222
MockProxyLatencies,
23+
MockListeningPortsResponse,
2324
} from "testHelpers/entities";
2425
import { AgentRow, LineWithID } from "./AgentRow";
2526
import { ProxyContext, getPreferredProxy } from "contexts/ProxyContext";
@@ -103,7 +104,15 @@ const storybookLogs: LineWithID[] = [
103104

104105
const meta: Meta<typeof AgentRow> = {
105106
title: "components/AgentRow",
106-
parameters: { chromatic },
107+
parameters: {
108+
chromatic,
109+
queries: [
110+
{
111+
key: ["portForward", MockWorkspaceAgent.id],
112+
data: MockListeningPortsResponse,
113+
},
114+
],
115+
},
107116
component: AgentRow,
108117
args: {
109118
storybookLogs,

0 commit comments

Comments
 (0)