Skip to content

Commit aa7adf8

Browse files
committed
:^)
1 parent cdc0ea2 commit aa7adf8

File tree

2 files changed

+86
-18
lines changed

2 files changed

+86
-18
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { type FC } from "react";
2+
import dayjs from "dayjs";
3+
import relativeTime from "dayjs/plugin/relativeTime";
4+
import { useTheme } from "@emotion/react";
5+
import { Stack } from "components/Stack/Stack";
6+
7+
dayjs.extend(relativeTime);
8+
9+
interface ConnectionStatusProps {
10+
lastUsedAt: string;
11+
}
12+
13+
export const ConnectionStatus: FC<ConnectionStatusProps> = ({ lastUsedAt }) => {
14+
const theme = useTheme();
15+
const t = dayjs(lastUsedAt);
16+
const now = dayjs();
17+
let message = t.fromNow();
18+
let circle = (
19+
<Circle color={theme.palette.text.secondary} variant="outlined" />
20+
);
21+
22+
if (t.isAfter(now.subtract(1, "hour"))) {
23+
circle = <Circle color={theme.roles.success.fill.solid} />;
24+
// Since the agent reports on a 10m interval,
25+
// the last_used_at can be inaccurate when recent.
26+
message = "Now";
27+
} else if (t.isAfter(now.subtract(3, "day"))) {
28+
circle = <Circle color={theme.palette.text.secondary} />;
29+
} else if (t.isAfter(now.subtract(1, "month"))) {
30+
circle = <Circle color={theme.roles.warning.fill.solid} />;
31+
} else if (t.isAfter(now.subtract(100, "year"))) {
32+
circle = <Circle color={theme.roles.error.fill.solid} />;
33+
} else {
34+
message = "Never";
35+
}
36+
37+
return (
38+
<Stack
39+
style={{ color: theme.palette.text.secondary }}
40+
direction="row"
41+
spacing={1}
42+
alignItems="center"
43+
>
44+
{circle}
45+
<span data-chromatic="ignore">{message}</span>
46+
</Stack>
47+
);
48+
};
49+
50+
type CircleProps = {
51+
color: string;
52+
variant?: "solid" | "outlined";
53+
};
54+
55+
const Circle: FC<CircleProps> = ({ color, variant = "solid" }) => {
56+
return (
57+
<div
58+
aria-hidden
59+
css={{
60+
width: 8,
61+
height: 8,
62+
backgroundColor: variant === "solid" ? color : undefined,
63+
border: variant === "outlined" ? `1px solid ${color}` : undefined,
64+
borderRadius: 9999,
65+
}}
66+
/>
67+
);
68+
};

site/src/pages/WorkspacePage/WorkspaceTopbar.tsx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import {
3333
shouldDisplayScheduleControls,
3434
} from "./WorkspaceScheduleControls";
3535
import { WorkspacePermissions } from "./permissions";
36-
import { LastUsed } from "pages/WorkspacesPage/LastUsed";
36+
import { ConnectionStatus } from "./ConnectionStatus";
3737

3838
export type WorkspaceError =
3939
| "getBuildsError"
@@ -201,6 +201,23 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
201201
</Popover>
202202
</TopbarData>
203203

204+
<ConnectionStatus lastUsedAt={workspace.last_used_at} />
205+
206+
{shouldDisplayScheduleControls(workspace) && (
207+
<TopbarData>
208+
<TopbarIcon>
209+
<Tooltip title="Schedule">
210+
<ScheduleOutlined aria-label="Schedule" />
211+
</Tooltip>
212+
</TopbarIcon>
213+
<WorkspaceScheduleControls
214+
workspace={workspace}
215+
template={template}
216+
canUpdateSchedule={canUpdateWorkspace}
217+
/>
218+
</TopbarData>
219+
)}
220+
204221
{shouldDisplayDormantData && (
205222
<TopbarData>
206223
<TopbarIcon>
@@ -220,23 +237,6 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
220237
</TopbarData>
221238
)}
222239

223-
{shouldDisplayScheduleControls(workspace) && (
224-
<TopbarData>
225-
<TopbarIcon>
226-
<Tooltip title="Schedule">
227-
<ScheduleOutlined aria-label="Schedule" />
228-
</Tooltip>
229-
</TopbarIcon>
230-
<WorkspaceScheduleControls
231-
workspace={workspace}
232-
template={template}
233-
canUpdateSchedule={canUpdateWorkspace}
234-
/>
235-
</TopbarData>
236-
)}
237-
238-
<LastUsed lastUsedAt={workspace.last_used_at} />
239-
240240
{quota && quota.budget > 0 && (
241241
<TopbarData>
242242
<TopbarIcon>

0 commit comments

Comments
 (0)