Skip to content

feat: add activity status and autostop reason to workspace overview #11987

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Feb 13, 2024
Prev Previous commit
Next Next commit
:^)
  • Loading branch information
aslilac committed Feb 7, 2024
commit aa7adf8adc714ded2079e64e615b54e3748ed141
68 changes: 68 additions & 0 deletions site/src/pages/WorkspacePage/ConnectionStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { type FC } from "react";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { useTheme } from "@emotion/react";
import { Stack } from "components/Stack/Stack";

dayjs.extend(relativeTime);

interface ConnectionStatusProps {
lastUsedAt: string;
}

export const ConnectionStatus: FC<ConnectionStatusProps> = ({ lastUsedAt }) => {
const theme = useTheme();
const t = dayjs(lastUsedAt);
const now = dayjs();
let message = t.fromNow();
let circle = (
<Circle color={theme.palette.text.secondary} variant="outlined" />
);

if (t.isAfter(now.subtract(1, "hour"))) {
circle = <Circle color={theme.roles.success.fill.solid} />;
// Since the agent reports on a 10m interval,
// the last_used_at can be inaccurate when recent.
message = "Now";
} else if (t.isAfter(now.subtract(3, "day"))) {
circle = <Circle color={theme.palette.text.secondary} />;
} else if (t.isAfter(now.subtract(1, "month"))) {
circle = <Circle color={theme.roles.warning.fill.solid} />;
} else if (t.isAfter(now.subtract(100, "year"))) {
circle = <Circle color={theme.roles.error.fill.solid} />;
} else {
message = "Never";
}

return (
<Stack
style={{ color: theme.palette.text.secondary }}
direction="row"
spacing={1}
alignItems="center"
>
{circle}
<span data-chromatic="ignore">{message}</span>
</Stack>
);
};

type CircleProps = {
color: string;
variant?: "solid" | "outlined";
};

const Circle: FC<CircleProps> = ({ color, variant = "solid" }) => {
return (
<div
aria-hidden
css={{
width: 8,
height: 8,
backgroundColor: variant === "solid" ? color : undefined,
border: variant === "outlined" ? `1px solid ${color}` : undefined,
borderRadius: 9999,
}}
/>
);
};
36 changes: 18 additions & 18 deletions site/src/pages/WorkspacePage/WorkspaceTopbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
shouldDisplayScheduleControls,
} from "./WorkspaceScheduleControls";
import { WorkspacePermissions } from "./permissions";
import { LastUsed } from "pages/WorkspacesPage/LastUsed";
import { ConnectionStatus } from "./ConnectionStatus";

export type WorkspaceError =
| "getBuildsError"
Expand Down Expand Up @@ -201,6 +201,23 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
</Popover>
</TopbarData>

<ConnectionStatus lastUsedAt={workspace.last_used_at} />

{shouldDisplayScheduleControls(workspace) && (
<TopbarData>
<TopbarIcon>
<Tooltip title="Schedule">
<ScheduleOutlined aria-label="Schedule" />
</Tooltip>
</TopbarIcon>
<WorkspaceScheduleControls
workspace={workspace}
template={template}
canUpdateSchedule={canUpdateWorkspace}
/>
</TopbarData>
)}

{shouldDisplayDormantData && (
<TopbarData>
<TopbarIcon>
Expand All @@ -220,23 +237,6 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
</TopbarData>
)}

{shouldDisplayScheduleControls(workspace) && (
<TopbarData>
<TopbarIcon>
<Tooltip title="Schedule">
<ScheduleOutlined aria-label="Schedule" />
</Tooltip>
</TopbarIcon>
<WorkspaceScheduleControls
workspace={workspace}
template={template}
canUpdateSchedule={canUpdateWorkspace}
/>
</TopbarData>
)}

<LastUsed lastUsedAt={workspace.last_used_at} />

{quota && quota.budget > 0 && (
<TopbarData>
<TopbarIcon>
Expand Down