Files
coder/site/src/components/WorkspaceStatusBar/WorkspaceStatusBar.tsx
Kyle Carberry 22ec366535 feat: Redesign workspaces page (#1450)
* feat: Improve navbar to be more compact

The navbar was unnecessarily large before, which made
the UI feel a bit bloaty from my perspective.

* Attempt to remove overrides

* Update theme

* Add text field

* Update theme to dark!

* Fix import ordering

* Fix page location

* Fix requested changes

* Add storybook for workspaces page view

* Add empty view

* Add tests for empty view

* Remove templates page

* Fix local port

* Remove templates from nav

* Fix e2e test

* Remove time.ts

* Remove dep

* Add background color to margins

* Merge status checking from workspace page

* Fix requested changes

* Fix workspace status tests
2022-05-16 16:52:54 -05:00

146 lines
4.1 KiB
TypeScript

import Box from "@material-ui/core/Box"
import Button from "@material-ui/core/Button"
import { makeStyles } from "@material-ui/core/styles"
import Typography from "@material-ui/core/Typography"
import React from "react"
import { Link } from "react-router-dom"
import * as TypesGen from "../../api/typesGenerated"
import { TitleIconSize } from "../../theme/constants"
import { combineClasses } from "../../util/combineClasses"
import { WorkspaceStatus } from "../../util/workspace"
import { Stack } from "../Stack/Stack"
import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection"
export const Language = {
stop: "Stop",
start: "Start",
retry: "Retry",
update: "Update",
settings: "Settings",
started: "Running",
stopped: "Stopped",
starting: "Building",
stopping: "Stopping",
canceled: "Canceled",
queued: "Queued",
error: "Build Failed",
loading: "Loading Status",
deleting: "Deleting",
deleted: "Deleted",
// "Canceling" would be misleading because it refers to a build, not the workspace.
// So just stall. When it is canceled it will appear as the error workspaceStatus.
canceling: "Loading Status",
}
export interface WorkspaceStatusBarProps {
organization?: TypesGen.Organization
workspace: TypesGen.Workspace
template?: TypesGen.Template
handleStart: () => void
handleStop: () => void
handleRetry: () => void
handleUpdate: () => void
workspaceStatus: WorkspaceStatus
}
/**
* Jobs submitted while another job is in progress will be discarded,
* so check whether workspace job status has reached completion (whether successful or not).
*/
const canAcceptJobs = (workspaceStatus: WorkspaceStatus) =>
["started", "stopped", "deleted", "error", "canceled"].includes(workspaceStatus)
/**
* Component for the header at the top of the workspace page
*/
export const WorkspaceStatusBar: React.FC<WorkspaceStatusBarProps> = ({
workspace,
handleStart,
handleStop,
handleRetry,
handleUpdate,
workspaceStatus,
}) => {
const styles = useStyles()
const settingsLink = "edit"
return (
<WorkspaceSection>
<Stack spacing={1}>
<div className={combineClasses([styles.horizontal, styles.reverse])}>
<div className={styles.horizontal}>
<Link className={styles.link} to={settingsLink}>
{Language.settings}
</Link>
</div>
</div>
<div className={styles.horizontal}>
<div className={styles.horizontal}>
<Typography variant="h4">{workspace.name}</Typography>
<Box className={styles.statusChip} role="status">
{Language[workspaceStatus]}
</Box>
</div>
<div className={styles.horizontal}>
{workspaceStatus === "started" && (
<Button onClick={handleStop} color="primary">
{Language.stop}
</Button>
)}
{workspaceStatus === "stopped" && (
<Button onClick={handleStart} color="primary">
{Language.start}
</Button>
)}
{workspaceStatus === "error" && (
<Button onClick={handleRetry} color="primary">
{Language.retry}
</Button>
)}
{workspace.outdated && canAcceptJobs(workspaceStatus) && (
<Button onClick={handleUpdate} color="primary">
{Language.update}
</Button>
)}
</div>
</div>
</Stack>
</WorkspaceSection>
)
}
const useStyles = makeStyles((theme) => {
return {
link: {
textDecoration: "none",
color: theme.palette.text.primary,
},
icon: {
width: TitleIconSize,
height: TitleIconSize,
},
horizontal: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
gap: theme.spacing(2),
},
reverse: {
flexDirection: "row-reverse",
},
statusChip: {
border: `solid 1px ${theme.palette.text.hint}`,
borderRadius: theme.shape.borderRadius,
padding: theme.spacing(1),
},
vertical: {
display: "flex",
flexDirection: "column",
},
}
})