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

Lines changed: 10 additions & 14 deletions
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

Lines changed: 83 additions & 96 deletions
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

Lines changed: 10 additions & 1 deletion
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy