mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add last used to Workspaces page (#3816)
This commit is contained in:
@@ -514,6 +514,7 @@ export interface Workspace {
|
||||
readonly name: string
|
||||
readonly autostart_schedule?: string
|
||||
readonly ttl_ms?: number
|
||||
readonly last_used_at: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaceresources.go
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Theme, useTheme } from "@material-ui/core/styles"
|
||||
import { FC } from "react"
|
||||
|
||||
import dayjs from "dayjs"
|
||||
import relativeTime from "dayjs/plugin/relativeTime"
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
interface WorkspaceLastUsedProps {
|
||||
lastUsedAt: string
|
||||
}
|
||||
|
||||
export const WorkspaceLastUsed: FC<WorkspaceLastUsedProps> = ({ lastUsedAt }) => {
|
||||
const theme: Theme = useTheme()
|
||||
|
||||
const t = dayjs(lastUsedAt)
|
||||
const now = dayjs()
|
||||
|
||||
let color = theme.palette.text.secondary
|
||||
let message = t.fromNow()
|
||||
|
||||
if (t.isAfter(now.subtract(1, "hour"))) {
|
||||
color = theme.palette.success.main
|
||||
// Since the agent reports on a 10m interval,
|
||||
// the last_used_at can be inaccurate when recent.
|
||||
message = "In the last hour"
|
||||
} else if (t.isAfter(now.subtract(1, "day"))) {
|
||||
color = theme.palette.primary.main
|
||||
} else if (t.isAfter(now.subtract(1, "month"))) {
|
||||
color = theme.palette.text.secondary
|
||||
} else if (t.isAfter(now.subtract(100, "year"))) {
|
||||
color = theme.palette.warning.light
|
||||
} else {
|
||||
color = theme.palette.error.light
|
||||
message = "Never"
|
||||
}
|
||||
|
||||
return <span style={{ color: color }}>{message}</span>
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from "../TableCellData/TableCellData"
|
||||
import { TableCellLink } from "../TableCellLink/TableCellLink"
|
||||
import { OutdatedHelpTooltip } from "../Tooltips"
|
||||
import { WorkspaceLastUsed } from "./WorkspaceLastUsed"
|
||||
|
||||
const Language = {
|
||||
upToDateLabel: "Up to date",
|
||||
@@ -64,6 +65,12 @@ export const WorkspacesRow: FC<
|
||||
}
|
||||
/>
|
||||
</TableCellLink>
|
||||
<TableCellLink to={workspacePageLink}>
|
||||
<TableCellData>
|
||||
<WorkspaceLastUsed lastUsedAt={workspace.last_used_at} />
|
||||
</TableCellData>
|
||||
</TableCellLink>
|
||||
|
||||
<TableCellLink to={workspacePageLink}>
|
||||
{workspace.outdated ? (
|
||||
<span className={styles.outdatedLabel}>
|
||||
|
||||
@@ -11,6 +11,7 @@ import { WorkspacesTableBody } from "./WorkspacesTableBody"
|
||||
const Language = {
|
||||
name: "Name",
|
||||
template: "Template",
|
||||
lastUsed: "Last Used",
|
||||
version: "Version",
|
||||
status: "Status",
|
||||
lastBuiltBy: "Last Built By",
|
||||
@@ -34,6 +35,7 @@ export const WorkspacesTable: FC<React.PropsWithChildren<WorkspacesTableProps>>
|
||||
<TableRow>
|
||||
<TableCell width="25%">{Language.name}</TableCell>
|
||||
<TableCell width="35%">{Language.template}</TableCell>
|
||||
<TableCell width="20%">{Language.lastUsed}</TableCell>
|
||||
<TableCell width="20%">{Language.version}</TableCell>
|
||||
<TableCell width="20%">{Language.status}</TableCell>
|
||||
<TableCell width="1%"></TableCell>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ComponentMeta, Story } from "@storybook/react"
|
||||
import dayjs from "dayjs"
|
||||
import { spawn } from "xstate"
|
||||
import { ProvisionerJobStatus, WorkspaceTransition } from "../../api/typesGenerated"
|
||||
import { MockWorkspace } from "../../testHelpers/entities"
|
||||
@@ -13,6 +14,7 @@ const createWorkspaceItemRef = (
|
||||
status: ProvisionerJobStatus,
|
||||
transition: WorkspaceTransition = "start",
|
||||
outdated = false,
|
||||
lastUsedAt = "0001-01-01",
|
||||
): WorkspaceItemMachineRef => {
|
||||
return spawn(
|
||||
workspaceItemMachine.withContext({
|
||||
@@ -27,6 +29,7 @@ const createWorkspaceItemRef = (
|
||||
status: status,
|
||||
},
|
||||
},
|
||||
last_used_at: lastUsedAt,
|
||||
},
|
||||
}),
|
||||
)
|
||||
@@ -48,6 +51,15 @@ const additionalWorkspaces: Record<string, WorkspaceItemMachineRef> = {
|
||||
succeededAndStop: createWorkspaceItemRef("succeeded", "stop"),
|
||||
runningAndDelete: createWorkspaceItemRef("running", "delete"),
|
||||
outdated: createWorkspaceItemRef("running", "delete", true),
|
||||
active: createWorkspaceItemRef("running", undefined, true, dayjs().toString()),
|
||||
today: createWorkspaceItemRef("running", undefined, true, dayjs().subtract(3, "hour").toString()),
|
||||
old: createWorkspaceItemRef("running", undefined, true, dayjs().subtract(1, "week").toString()),
|
||||
veryOld: createWorkspaceItemRef(
|
||||
"running",
|
||||
undefined,
|
||||
true,
|
||||
dayjs().subtract(1, "month").subtract(4, "day").toString(),
|
||||
),
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -236,6 +236,7 @@ export const MockWorkspace: TypesGen.Workspace = {
|
||||
autostart_schedule: MockWorkspaceAutostartEnabled.schedule,
|
||||
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours as milliseconds
|
||||
latest_build: MockWorkspaceBuild,
|
||||
last_used_at: "",
|
||||
}
|
||||
|
||||
export const MockStoppedWorkspace: TypesGen.Workspace = {
|
||||
|
||||
Reference in New Issue
Block a user