diff --git a/site/src/components/DeploySettingsLayout/OptionsTable.tsx b/site/src/components/DeploySettingsLayout/OptionsTable.tsx index 1f09a66c02b94..b50e4f18242c0 100644 --- a/site/src/components/DeploySettingsLayout/OptionsTable.tsx +++ b/site/src/components/DeploySettingsLayout/OptionsTable.tsx @@ -1,10 +1,13 @@ -import { makeStyles } from "@mui/styles"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableCell from "@mui/material/TableCell"; import TableContainer from "@mui/material/TableContainer"; import TableHead from "@mui/material/TableHead"; import TableRow from "@mui/material/TableRow"; +import { type FC } from "react"; +import Box from "@mui/material/Box"; +import { css } from "@emotion/react"; +import type { ClibaseOption } from "api/typesGenerated"; import { OptionConfig, OptionConfigFlag, @@ -12,23 +15,30 @@ import { OptionName, OptionValue, } from "components/DeploySettingsLayout/Option"; -import { FC } from "react"; import { optionValue } from "./optionValue"; -import Box from "@mui/material/Box"; -import { ClibaseOption } from "api/typesGenerated"; const OptionsTable: FC<{ options: ClibaseOption[]; }> = ({ options }) => { - const styles = useStyles(); - if (options.length === 0) { return

No options to configure

; } return ( - +
css` + & td { + padding-top: ${theme.spacing(3)}; + padding-bottom: ${theme.spacing(3)}; + } + + & td:last-child, + & th:last-child { + padding-left: ${theme.spacing(4)}; + } + `} + > Option @@ -96,17 +106,4 @@ const OptionsTable: FC<{ ); }; -const useStyles = makeStyles((theme) => ({ - table: { - "& td": { - paddingTop: theme.spacing(3), - paddingBottom: theme.spacing(3), - }, - - "& td:last-child, & th:last-child": { - paddingLeft: theme.spacing(4), - }, - }, -})); - export default OptionsTable; diff --git a/site/src/components/Dialogs/ConfirmDialog/ConfirmDialog.tsx b/site/src/components/Dialogs/ConfirmDialog/ConfirmDialog.tsx index 053cde5b48886..50f0c248509d6 100644 --- a/site/src/components/Dialogs/ConfirmDialog/ConfirmDialog.tsx +++ b/site/src/components/Dialogs/ConfirmDialog/ConfirmDialog.tsx @@ -1,15 +1,12 @@ import DialogActions from "@mui/material/DialogActions"; -import { makeStyles } from "@mui/styles"; -import { ReactNode, FC, PropsWithChildren } from "react"; +import { type Interpolation, type Theme } from "@emotion/react"; +import { type FC, type PropsWithChildren, type ReactNode } from "react"; import { Dialog, DialogActionButtons, DialogActionButtonsProps, } from "../Dialog"; -import { ConfirmDialogType } from "../types"; -import Checkbox from "@mui/material/Checkbox"; -import FormControlLabel from "@mui/material/FormControlLabel"; -import { Stack } from "@mui/system"; +import type { ConfirmDialogType } from "../types"; interface ConfirmDialogTypeConfig { confirmText: ReactNode; @@ -58,8 +55,8 @@ export interface ConfirmDialogProps readonly title: string; } -const useStyles = makeStyles((theme) => ({ - dialogWrapper: { +const styles = { + dialogWrapper: (theme) => ({ "& .MuiPaper-root": { background: theme.palette.background.paper, border: `1px solid ${theme.palette.divider}`, @@ -69,19 +66,19 @@ const useStyles = makeStyles((theme) => ({ "& .MuiDialogActions-spacing": { padding: `0 ${theme.spacing(5)} ${theme.spacing(5)}`, }, - }, - dialogContent: { + }), + dialogContent: (theme) => ({ color: theme.palette.text.secondary, padding: theme.spacing(5), - }, - dialogTitle: { + }), + dialogTitle: (theme) => ({ margin: 0, marginBottom: theme.spacing(2), color: theme.palette.text.primary, fontWeight: 400, fontSize: theme.spacing(2.5), - }, - dialogDescription: { + }), + dialogDescription: (theme) => ({ color: theme.palette.text.secondary, lineHeight: "160%", fontSize: 16, @@ -97,8 +94,8 @@ const useStyles = makeStyles((theme) => ({ "& > p": { margin: theme.spacing(1, 0), }, - }, -})); + }), +} satisfies Record>; /** * Quick-use version of the Dialog component with slightly alternative styles, @@ -117,8 +114,6 @@ export const ConfirmDialog: FC> = ({ title, type = "info", }) => { - const styles = useStyles({ type }); - const defaults = CONFIRM_DIALOG_DEFAULTS[type]; if (typeof hideCancel === "undefined") { @@ -127,16 +122,14 @@ export const ConfirmDialog: FC> = ({ return ( -
-

{title}

- {description && ( -
{description}
- )} +
+

{title}

+ {description &&
{description}
}
@@ -154,169 +147,3 @@ export const ConfirmDialog: FC> = ({
); }; - -export interface ScheduleDialogProps extends ConfirmDialogProps { - readonly inactiveWorkspacesToGoDormant: number; - readonly inactiveWorkspacesToGoDormantInWeek: number; - readonly dormantWorkspacesToBeDeleted: number; - readonly dormantWorkspacesToBeDeletedInWeek: number; - readonly updateDormantWorkspaces: (confirm: boolean) => void; - readonly updateInactiveWorkspaces: (confirm: boolean) => void; - readonly dormantValueChanged: boolean; - readonly deletionValueChanged: boolean; -} - -export const ScheduleDialog: FC> = ({ - cancelText, - confirmLoading, - disabled = false, - hideCancel, - onClose, - onConfirm, - type, - open = false, - title, - inactiveWorkspacesToGoDormant, - inactiveWorkspacesToGoDormantInWeek, - dormantWorkspacesToBeDeleted, - dormantWorkspacesToBeDeletedInWeek, - updateDormantWorkspaces, - updateInactiveWorkspaces, - dormantValueChanged, - deletionValueChanged, -}) => { - const styles = useScheduleStyles({ type }); - - const defaults = CONFIRM_DIALOG_DEFAULTS["delete"]; - - if (typeof hideCancel === "undefined") { - hideCancel = defaults.hideCancel; - } - - const showDormancyWarning = - dormantValueChanged && - (inactiveWorkspacesToGoDormant > 0 || - inactiveWorkspacesToGoDormantInWeek > 0); - const showDeletionWarning = - deletionValueChanged && - (dormantWorkspacesToBeDeleted > 0 || - dormantWorkspacesToBeDeletedInWeek > 0); - - return ( - -
-

{title}

- <> - {showDormancyWarning && ( - <> -

{"Dormancy Threshold"}

- -
{` - This change will result in ${inactiveWorkspacesToGoDormant} workspaces being immediately transitioned to the dormant state and ${inactiveWorkspacesToGoDormantInWeek} over the next seven days. To prevent this, do you want to reset the inactivity period for all template workspaces?`}
- { - updateInactiveWorkspaces(e.target.checked); - }} - /> - } - label="Reset" - /> -
- - )} - - {showDeletionWarning && ( - <> -

{"Dormancy Auto-Deletion"}

- -
{`This change will result in ${dormantWorkspacesToBeDeleted} workspaces being immediately deleted and ${dormantWorkspacesToBeDeletedInWeek} over the next 7 days. To prevent this, do you want to reset the dormancy period for all template workspaces?`}
- { - updateDormantWorkspaces(e.target.checked); - }} - /> - } - label="Reset" - /> -
- - )} - -
- - - - -
- ); -}; - -const useScheduleStyles = makeStyles((theme) => ({ - dialogWrapper: { - "& .MuiPaper-root": { - background: theme.palette.background.paper, - border: `1px solid ${theme.palette.divider}`, - width: "100%", - maxWidth: theme.spacing(125), - }, - "& .MuiDialogActions-spacing": { - padding: `0 ${theme.spacing(5)} ${theme.spacing(5)}`, - }, - }, - dialogContent: { - color: theme.palette.text.secondary, - padding: theme.spacing(5), - }, - dialogTitle: { - margin: 0, - marginBottom: theme.spacing(2), - color: theme.palette.text.primary, - fontWeight: 400, - fontSize: theme.spacing(2.5), - }, - dialogDescription: { - color: theme.palette.text.secondary, - lineHeight: "160%", - fontSize: 16, - - "& strong": { - color: theme.palette.text.primary, - }, - - "& p:not(.MuiFormHelperText-root)": { - margin: 0, - }, - - "& > p": { - margin: theme.spacing(1, 0), - }, - }, -})); diff --git a/site/src/components/Dialogs/Dialog.tsx b/site/src/components/Dialogs/Dialog.tsx index c1c606fd06268..0c81598354db5 100644 --- a/site/src/components/Dialogs/Dialog.tsx +++ b/site/src/components/Dialogs/Dialog.tsx @@ -1,19 +1,18 @@ import MuiDialog, { DialogProps as MuiDialogProps } from "@mui/material/Dialog"; -import { makeStyles } from "@mui/styles"; -import * as React from "react"; +import { type ReactNode } from "react"; import { colors } from "theme/colors"; -import { combineClasses } from "utils/combineClasses"; import { LoadingButton, LoadingButtonProps, } from "../LoadingButton/LoadingButton"; import { ConfirmDialogType } from "./types"; +import { type Interpolation, type Theme } from "@emotion/react"; export interface DialogActionButtonsProps { /** Text to display in the cancel button */ cancelText?: string; /** Text to display in the confirm button */ - confirmText?: React.ReactNode; + confirmText?: ReactNode; /** Whether or not confirm is loading, also disables cancel when true */ confirmLoading?: boolean; /** Whether or not this is a confirm dialog */ @@ -46,8 +45,6 @@ export const DialogActionButtons: React.FC = ({ onConfirm, type = "info", }) => { - const styles = useButtonStyles({ type }); - return ( <> {onCancel && ( @@ -65,10 +62,10 @@ export const DialogActionButtons: React.FC = ({ loading={confirmLoading} disabled={disabled} type="submit" - className={combineClasses({ - [styles.errorButton]: type === "delete", - [styles.successButton]: type === "success", - })} + css={[ + type === "delete" && styles.errorButton, + type === "success" && styles.successButton, + ]} > {confirmText} @@ -77,8 +74,8 @@ export const DialogActionButtons: React.FC = ({ ); }; -const useButtonStyles = makeStyles((theme) => ({ - errorButton: { +const styles = { + errorButton: (theme) => ({ "&.MuiButton-contained": { backgroundColor: colors.red[10], borderColor: colors.red[9], @@ -95,8 +92,8 @@ const useButtonStyles = makeStyles((theme) => ({ color: colors.red[9], }, }, - }, - successButton: { + }), + successButton: (theme) => ({ "&.MuiButton-contained": { backgroundColor: theme.palette.success.main, color: theme.palette.primary.contrastText, @@ -145,8 +142,8 @@ const useButtonStyles = makeStyles((theme) => ({ color: theme.palette.text.secondary, }, }, - }, -})); + }), +} satisfies Record>; export type DialogProps = MuiDialogProps; diff --git a/site/src/components/Expander/Expander.tsx b/site/src/components/Expander/Expander.tsx index 25fac1d7ad2ec..c736f73168ebc 100644 --- a/site/src/components/Expander/Expander.tsx +++ b/site/src/components/Expander/Expander.tsx @@ -1,9 +1,8 @@ +import { type Interpolation, type Theme } from "@emotion/react"; import Collapse from "@mui/material/Collapse"; import Link from "@mui/material/Link"; -import makeStyles from "@mui/styles/makeStyles"; import { DropdownArrow } from "components/DropdownArrow/DropdownArrow"; import { type FC, type PropsWithChildren } from "react"; -import { combineClasses } from "utils/combineClasses"; export interface ExpanderProps { expanded: boolean; @@ -15,29 +14,27 @@ export const Expander: FC> = ({ setExpanded, children, }) => { - const styles = useStyles(); - const toggleExpanded = () => setExpanded(!expanded); return ( <> {!expanded && ( - - + + Click here to learn more )} -
{children}
+
{children}
{expanded && ( - + Click here to hide @@ -47,18 +44,18 @@ export const Expander: FC> = ({ ); }; -const useStyles = makeStyles((theme) => ({ - expandLink: { +const styles = { + expandLink: (theme) => ({ cursor: "pointer", color: theme.palette.text.secondary, - }, - collapseLink: { + }), + collapseLink: (theme) => ({ marginTop: theme.spacing(2), - }, - text: { + }), + text: (theme) => ({ display: "flex", alignItems: "center", color: theme.palette.text.secondary, fontSize: theme.typography.caption.fontSize, - }, -})); + }), +} satisfies Record>; diff --git a/site/src/components/Form/Form.tsx b/site/src/components/Form/Form.tsx index b487050513484..92356b38ec1bc 100644 --- a/site/src/components/Form/Form.tsx +++ b/site/src/components/Form/Form.tsx @@ -1,18 +1,18 @@ -import { makeStyles } from "@mui/styles"; -import { AlphaBadge } from "components/DeploySettingsLayout/Badges"; -import { - FormFooterProps as BaseFormFooterProps, - FormFooter as BaseFormFooter, -} from "components/FormFooter/FormFooter"; -import { Stack } from "components/Stack/Stack"; +import { type Interpolation, type Theme, useTheme } from "@emotion/react"; import { createContext, - FC, - HTMLProps, - PropsWithChildren, + type FC, + type HTMLProps, + type PropsWithChildren, useContext, } from "react"; -import { combineClasses } from "utils/combineClasses"; +import { AlphaBadge } from "components/DeploySettingsLayout/Badges"; +import { Stack } from "components/Stack/Stack"; +import { + FormFooter as BaseFormFooter, + FormFooterProps, + type FormFooterStyles, +} from "../FormFooter/FormFooter"; type FormContextValue = { direction?: "horizontal" | "vertical" }; @@ -24,14 +24,22 @@ type FormProps = HTMLProps & { direction?: FormContextValue["direction"]; }; -export const Form: FC = ({ direction, className, ...formProps }) => { - const styles = useStyles({ direction }); +export const Form: FC = ({ direction, ...formProps }) => { + const theme = useTheme(); return (
); @@ -71,28 +79,50 @@ export const FormSection: FC< alpha?: boolean; } > = ({ children, title, description, classes = {}, alpha = false }) => { - const formContext = useContext(FormContext); - const styles = useStyles(formContext); + const { direction } = useContext(FormContext); + const theme = useTheme(); return ( -
+

{title} {alpha && }

-
{description}
+
{description}
{children} @@ -101,108 +131,55 @@ export const FormSection: FC< }; export const FormFields: FC = ({ children }) => { - const styles = useStyles(); return ( - + {children} ); }; -export const FormFooter: FC = (props) => { - const formFooterStyles = useFormFooterStyles(); - return ( - - ); -}; -const getFlexDirection = ({ direction }: FormContextValue = {}): - | "row" - | "column" => - direction === "horizontal" ? ("row" as const) : ("column" as const); - -const useStyles = makeStyles((theme) => ({ - form: { - display: "flex", - flexDirection: "column", - gap: ({ direction }: FormContextValue = {}) => - direction === "horizontal" ? theme.spacing(10) : theme.spacing(5), - - [theme.breakpoints.down("md")]: { - gap: theme.spacing(8), - }, - }, - - formSection: { - display: "flex", - alignItems: "flex-start", - gap: ({ direction }: FormContextValue = {}) => - direction === "horizontal" ? theme.spacing(15) : theme.spacing(3), - flexDirection: getFlexDirection, - - [theme.breakpoints.down("md")]: { - flexDirection: "column", - gap: theme.spacing(2), - }, - }, - - formSectionInfo: { - width: "100%", - maxWidth: ({ direction }: FormContextValue = {}) => - direction === "horizontal" ? 312 : undefined, - flexShrink: 0, - position: ({ direction }: FormContextValue = {}) => - direction === "horizontal" ? "sticky" : undefined, - top: theme.spacing(3), - - [theme.breakpoints.down("md")]: { - width: "100%", - position: "initial" as const, - }, - }, - - formSectionInfoTitle: { +const styles = { + formSectionInfoTitle: (theme) => ({ fontSize: 20, color: theme.palette.text.primary, fontWeight: 400, margin: 0, marginBottom: theme.spacing(1), - }, + }), - formSectionInfoTitleAlpha: { + formSectionInfoTitleAlpha: (theme) => ({ display: "flex", flexDirection: "row", alignItems: "center", gap: theme.spacing(1.5), - }, + }), - formSectionInfoDescription: { + formSectionInfoDescription: (theme) => ({ fontSize: 14, color: theme.palette.text.secondary, lineHeight: "160%", margin: 0, - }, + }), formSectionFields: { width: "100%", }, -})); +} satisfies Record>; + +export const FormFooter = (props: Exclude) => ( + +); -const useFormFooterStyles = makeStyles((theme) => ({ - button: { +const footerStyles = { + button: (theme) => ({ minWidth: theme.spacing(23), [theme.breakpoints.down("md")]: { width: "100%", }, - }, - footer: { + }), + + footer: (theme) => ({ display: "flex", alignItems: "center", justifyContent: "flex-start", @@ -213,5 +190,5 @@ const useFormFooterStyles = makeStyles((theme) => ({ flexDirection: "column", gap: theme.spacing(1), }, - }, -})); + }), +} satisfies FormFooterStyles; diff --git a/site/src/components/FormFooter/FormFooter.tsx b/site/src/components/FormFooter/FormFooter.tsx index 100cf6578785b..7221aaf6a217d 100644 --- a/site/src/components/FormFooter/FormFooter.tsx +++ b/site/src/components/FormFooter/FormFooter.tsx @@ -1,15 +1,18 @@ import Button from "@mui/material/Button"; -import { makeStyles } from "@mui/styles"; -import { ClassNameMap } from "@mui/styles/withStyles"; -import { FC } from "react"; +import { type FC } from "react"; import { LoadingButton } from "../LoadingButton/LoadingButton"; +import { Interpolation, Theme } from "@emotion/react"; export const Language = { cancelLabel: "Cancel", defaultSubmitLabel: "Submit", }; -type FormFooterStyles = ClassNameMap<"footer" | "button">; +export interface FormFooterStyles { + footer: Interpolation; + button: Interpolation; +} + export interface FormFooterProps { onCancel: () => void; isLoading: boolean; @@ -23,15 +26,15 @@ export const FormFooter: FC = ({ isLoading, submitDisabled, submitLabel = Language.defaultSubmitLabel, - styles = defaultStyles(), + styles = defaultStyles, }) => { return ( -
+
= ({