coder/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.tsx

174 lines
5.2 KiB
TypeScript

import Button from "@material-ui/core/Button"
import IconButton from "@material-ui/core/IconButton"
import Popover from "@material-ui/core/Popover"
import { makeStyles } from "@material-ui/core/styles"
import Tooltip from "@material-ui/core/Tooltip"
import AddIcon from "@material-ui/icons/Add"
import RemoveIcon from "@material-ui/icons/Remove"
import ScheduleIcon from "@material-ui/icons/Schedule"
import dayjs from "dayjs"
import advancedFormat from "dayjs/plugin/advancedFormat"
import duration from "dayjs/plugin/duration"
import relativeTime from "dayjs/plugin/relativeTime"
import timezone from "dayjs/plugin/timezone"
import utc from "dayjs/plugin/utc"
import { useRef, useState } from "react"
import { useTranslation } from "react-i18next"
import { Workspace } from "../../api/typesGenerated"
import { isWorkspaceOn } from "../../util/workspace"
import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule"
import { WorkspaceScheduleLabel } from "./WorkspaceScheduleLabel"
// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're
// sorted alphabetically.
dayjs.extend(utc)
dayjs.extend(advancedFormat)
dayjs.extend(duration)
dayjs.extend(relativeTime)
dayjs.extend(timezone)
export const shouldDisplayPlusMinus = (workspace: Workspace): boolean => {
return isWorkspaceOn(workspace) && Boolean(workspace.latest_build.deadline)
}
export interface WorkspaceScheduleButtonProps {
workspace: Workspace
onDeadlinePlus: () => void
onDeadlineMinus: () => void
deadlineMinusEnabled: () => boolean
deadlinePlusEnabled: () => boolean
canUpdateWorkspace: boolean
}
export const WorkspaceScheduleButton: React.FC<WorkspaceScheduleButtonProps> = ({
workspace,
onDeadlinePlus,
onDeadlineMinus,
deadlinePlusEnabled,
deadlineMinusEnabled,
canUpdateWorkspace,
}) => {
const { t } = useTranslation("workspacePage")
const anchorRef = useRef<HTMLButtonElement>(null)
const [isOpen, setIsOpen] = useState(false)
const id = isOpen ? "schedule-popover" : undefined
const styles = useStyles()
const onClose = () => {
setIsOpen(false)
}
return (
<span className={styles.wrapper}>
<span className={styles.label}>
<WorkspaceScheduleLabel workspace={workspace} />
{canUpdateWorkspace && shouldDisplayPlusMinus(workspace) && (
<span className={styles.actions}>
<IconButton
className={styles.iconButton}
size="small"
disabled={!deadlineMinusEnabled()}
onClick={onDeadlineMinus}
>
<Tooltip title={t("workspaceScheduleButton.editDeadlineMinus")}>
<RemoveIcon />
</Tooltip>
</IconButton>
<IconButton
className={styles.iconButton}
size="small"
disabled={!deadlinePlusEnabled()}
onClick={onDeadlinePlus}
>
<Tooltip title={t("workspaceScheduleButton.editDeadlinePlus")}>
<AddIcon />
</Tooltip>
</IconButton>
</span>
)}
</span>
<>
<Button
ref={anchorRef}
startIcon={<ScheduleIcon />}
onClick={() => {
setIsOpen(true)
}}
className={styles.scheduleButton}
>
{t("workspaceScheduleButton.schedule")}
</Button>
<Popover
classes={{ paper: styles.popoverPaper }}
id={id}
open={isOpen}
anchorEl={anchorRef.current}
onClose={onClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
>
<WorkspaceSchedule workspace={workspace} canUpdateWorkspace={canUpdateWorkspace} />
</Popover>
</>
</span>
)
}
const useStyles = makeStyles((theme) => ({
wrapper: {
display: "inline-flex",
alignItems: "center",
border: `1px solid ${theme.palette.divider}`,
borderRadius: `${theme.shape.borderRadius}px`,
[theme.breakpoints.down("sm")]: {
flexDirection: "column",
},
},
label: {
borderRight: 0,
padding: "0 8px 0 16px",
color: theme.palette.text.secondary,
[theme.breakpoints.down("sm")]: {
width: "100%",
display: "flex",
alignItems: "center",
padding: theme.spacing(1.5, 2),
},
},
actions: {
[theme.breakpoints.down("sm")]: {
marginLeft: "auto",
display: "flex",
paddingLeft: theme.spacing(1),
marginRight: -theme.spacing(1),
},
},
scheduleButton: {
border: "none",
borderLeft: `1px solid ${theme.palette.divider}`,
borderRadius: `0px ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px 0px`,
flexShrink: 0,
[theme.breakpoints.down("sm")]: {
width: "100%",
borderLeft: 0,
borderTop: `1px solid ${theme.palette.divider}`,
borderRadius: `0 0 ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px`,
},
},
iconButton: {
borderRadius: theme.shape.borderRadius,
},
popoverPaper: {
padding: `${theme.spacing(2)}px ${theme.spacing(3)}px ${theme.spacing(3)}px`,
},
}))