mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
feat: Workspace StatusBar (#1362)
* Move component and prep * Make WorkspaceSection more reusable * Lay out elements * Layout tweaks * Add outdated to Workspace type * Fill out status bar component * Format * Add transition to types * Add api handlers for build toggle * Format * Parallelize machine * Lay out basics of build submachine * Pipe start and stop events through - needs status * Attempt at a machine It's so big, but collapsing start and stop made it hard to distinguish retry from toggle * Update mock * Render status and buttons * Fix type error on template page * Move Settings * Format * Keep refreshed workspace * Make it switch workspaces * Lint * Fix relative api path * Test * Fix polling * Add loading workspace state * Format * Add stub settings page * Format * Lint * Get rid of let * Add update * Make start use version id Important for update * Fix imports * Add polling for outdated * Rely on context instead of finite state for status * Handle canceling * Fix tests * Format * Display errors so users know when button presses didn't work * Fix api typo, remove logging * Lint * Simplify type Co-authored-by: G r e y <grey@coder.com> * Add type, extract helper Co-authored-by: G r e y <grey@coder.com>
This commit is contained in:
155
site/src/components/WorkspaceStatusBar/WorkspaceStatusBar.tsx
Normal file
155
site/src/components/WorkspaceStatusBar/WorkspaceStatusBar.tsx
Normal file
@ -0,0 +1,155 @@
|
||||
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 { WorkspaceStatus } from "../../pages/WorkspacePage/WorkspacePage"
|
||||
import { TitleIconSize } from "../../theme/constants"
|
||||
import { combineClasses } from "../../util/combineClasses"
|
||||
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",
|
||||
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"].includes(workspaceStatus)
|
||||
|
||||
/**
|
||||
* Component for the header at the top of the workspace page
|
||||
*/
|
||||
export const WorkspaceStatusBar: React.FC<WorkspaceStatusBarProps> = ({
|
||||
organization,
|
||||
template,
|
||||
workspace,
|
||||
handleStart,
|
||||
handleStop,
|
||||
handleRetry,
|
||||
handleUpdate,
|
||||
workspaceStatus,
|
||||
}) => {
|
||||
const styles = useStyles()
|
||||
|
||||
const templateLink = `/templates/${organization?.name}/${template?.name}`
|
||||
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>
|
||||
|
||||
{organization && template && (
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
Back to{" "}
|
||||
<Link className={styles.link} to={templateLink}>
|
||||
{template.name}
|
||||
</Link>
|
||||
</Typography>
|
||||
)}
|
||||
</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",
|
||||
},
|
||||
}
|
||||
})
|
Reference in New Issue
Block a user