mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
refactor(site): Refactor alerts (#7587)
This commit is contained in:
@@ -128,6 +128,10 @@ rules:
|
||||
message:
|
||||
"You should use the Avatar component provided on
|
||||
components/Avatar/Avatar"
|
||||
- name: "@mui/material/Alert"
|
||||
message:
|
||||
"You should use the Alert component provided on
|
||||
components/Alert/Alert"
|
||||
no-unused-vars: "off"
|
||||
"object-curly-spacing": "off"
|
||||
react-hooks/exhaustive-deps: warn
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Alert } from "./Alert"
|
||||
import Button from "@mui/material/Button"
|
||||
import Link from "@mui/material/Link"
|
||||
import type { Meta, StoryObj } from "@storybook/react"
|
||||
|
||||
const meta: Meta<typeof Alert> = {
|
||||
title: "components/Alert",
|
||||
component: Alert,
|
||||
}
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof Alert>
|
||||
|
||||
const ExampleAction = (
|
||||
<Button onClick={() => null} size="small" variant="text">
|
||||
Button
|
||||
</Button>
|
||||
)
|
||||
|
||||
export const Warning: Story = {
|
||||
args: {
|
||||
children: "This is a warning",
|
||||
severity: "warning",
|
||||
},
|
||||
}
|
||||
|
||||
export const WarningWithDismiss: Story = {
|
||||
args: {
|
||||
children: "This is a warning",
|
||||
dismissible: true,
|
||||
severity: "warning",
|
||||
},
|
||||
}
|
||||
|
||||
export const WarningWithAction: Story = {
|
||||
args: {
|
||||
children: "This is a warning",
|
||||
actions: [ExampleAction],
|
||||
severity: "warning",
|
||||
},
|
||||
}
|
||||
|
||||
export const WarningWithActionAndDismiss: Story = {
|
||||
args: {
|
||||
children: "This is a warning",
|
||||
actions: [ExampleAction],
|
||||
dismissible: true,
|
||||
severity: "warning",
|
||||
},
|
||||
}
|
||||
|
||||
export const WithChildren: Story = {
|
||||
args: {
|
||||
severity: "warning",
|
||||
children: (
|
||||
<div>
|
||||
This is a message with a <Link href="#">link</Link>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { useState, FC, ReactNode, PropsWithChildren } from "react"
|
||||
import Collapse from "@mui/material/Collapse"
|
||||
// eslint-disable-next-line no-restricted-imports -- It is the base component
|
||||
import MuiAlert, { AlertProps as MuiAlertProps } from "@mui/material/Alert"
|
||||
import Button from "@mui/material/Button"
|
||||
|
||||
export interface AlertProps extends PropsWithChildren {
|
||||
severity: MuiAlertProps["severity"]
|
||||
actions?: ReactNode[]
|
||||
dismissible?: boolean
|
||||
onRetry?: () => void
|
||||
onDismiss?: () => void
|
||||
}
|
||||
|
||||
export const Alert: FC<AlertProps> = ({
|
||||
children,
|
||||
actions = [],
|
||||
onRetry,
|
||||
dismissible,
|
||||
severity,
|
||||
onDismiss,
|
||||
}) => {
|
||||
const [open, setOpen] = useState(true)
|
||||
|
||||
return (
|
||||
<Collapse in={open}>
|
||||
<MuiAlert
|
||||
severity={severity}
|
||||
action={
|
||||
<>
|
||||
{/* CTAs passed in by the consumer */}
|
||||
{actions.length > 0 &&
|
||||
actions.map((action) => <div key={String(action)}>{action}</div>)}
|
||||
|
||||
{/* retry CTA */}
|
||||
{onRetry && (
|
||||
<Button variant="text" size="small" onClick={onRetry}>
|
||||
Retry
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* close CTA */}
|
||||
{dismissible && (
|
||||
<Button
|
||||
variant="text"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
onDismiss && onDismiss()
|
||||
}}
|
||||
data-testid="dismiss-banner-btn"
|
||||
>
|
||||
Dismiss
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</MuiAlert>
|
||||
</Collapse>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import Button from "@mui/material/Button"
|
||||
import { mockApiError } from "testHelpers/entities"
|
||||
import type { Meta, StoryObj } from "@storybook/react"
|
||||
import { action } from "@storybook/addon-actions"
|
||||
import { ErrorAlert } from "./ErrorAlert"
|
||||
|
||||
const mockError = mockApiError({
|
||||
message: "Email or password was invalid",
|
||||
detail: "Password is invalid",
|
||||
})
|
||||
|
||||
const meta: Meta<typeof ErrorAlert> = {
|
||||
title: "components/ErrorAlert",
|
||||
component: ErrorAlert,
|
||||
args: {
|
||||
error: mockError,
|
||||
dismissible: false,
|
||||
onRetry: undefined,
|
||||
},
|
||||
}
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof ErrorAlert>
|
||||
|
||||
const ExampleAction = (
|
||||
<Button onClick={() => null} size="small" variant="text">
|
||||
Button
|
||||
</Button>
|
||||
)
|
||||
|
||||
export const WithOnlyMessage: Story = {
|
||||
args: {
|
||||
error: mockApiError({
|
||||
message: "Email or password was invalid",
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
export const WithDismiss: Story = {
|
||||
args: {
|
||||
dismissible: true,
|
||||
},
|
||||
}
|
||||
|
||||
export const WithAction: Story = {
|
||||
args: {
|
||||
actions: [ExampleAction],
|
||||
},
|
||||
}
|
||||
|
||||
export const WithActionAndDismiss: Story = {
|
||||
args: {
|
||||
actions: [ExampleAction],
|
||||
dismissible: true,
|
||||
},
|
||||
}
|
||||
|
||||
export const WithRetry: Story = {
|
||||
args: {
|
||||
onRetry: action("retry"),
|
||||
dismissible: true,
|
||||
},
|
||||
}
|
||||
|
||||
export const WithActionRetryAndDismiss: Story = {
|
||||
args: {
|
||||
actions: [ExampleAction],
|
||||
onRetry: action("retry"),
|
||||
dismissible: true,
|
||||
},
|
||||
}
|
||||
|
||||
export const WithNonApiError: Story = {
|
||||
args: {
|
||||
error: new Error("Non API error here"),
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { AlertProps, Alert } from "./Alert"
|
||||
import AlertTitle from "@mui/material/AlertTitle"
|
||||
import Box from "@mui/material/Box"
|
||||
import { getErrorMessage, getErrorDetail } from "api/errors"
|
||||
import { FC } from "react"
|
||||
|
||||
export const ErrorAlert: FC<
|
||||
Omit<AlertProps, "severity" | "children"> & { error: unknown }
|
||||
> = ({ error, ...alertProps }) => {
|
||||
const message = getErrorMessage(error, "Something went wrong.")
|
||||
const detail = getErrorDetail(error)
|
||||
|
||||
return (
|
||||
<Alert severity="error" {...alertProps}>
|
||||
{detail ? (
|
||||
<>
|
||||
<AlertTitle>{message}</AlertTitle>
|
||||
<Box
|
||||
component="span"
|
||||
color={(theme) => theme.palette.text.secondary}
|
||||
fontSize={13}
|
||||
data-chromatic="ignore"
|
||||
>
|
||||
{detail}
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
message
|
||||
)}
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import { Story } from "@storybook/react"
|
||||
import { AlertBanner } from "./AlertBanner"
|
||||
import Button from "@mui/material/Button"
|
||||
import { mockApiError } from "testHelpers/entities"
|
||||
import { AlertBannerProps } from "./alertTypes"
|
||||
import Link from "@mui/material/Link"
|
||||
|
||||
export default {
|
||||
title: "components/AlertBanner",
|
||||
component: AlertBanner,
|
||||
}
|
||||
|
||||
const ExampleAction = (
|
||||
<Button onClick={() => null} size="small">
|
||||
Button
|
||||
</Button>
|
||||
)
|
||||
|
||||
const mockError = mockApiError({
|
||||
message: "Email or password was invalid",
|
||||
detail: "Password is invalid",
|
||||
})
|
||||
|
||||
const Template: Story<AlertBannerProps> = (args) => <AlertBanner {...args} />
|
||||
|
||||
export const Warning = Template.bind({})
|
||||
Warning.args = {
|
||||
text: "This is a warning",
|
||||
severity: "warning",
|
||||
}
|
||||
|
||||
export const ErrorWithDefaultMessage = Template.bind({})
|
||||
ErrorWithDefaultMessage.args = {
|
||||
text: "This is an error",
|
||||
severity: "error",
|
||||
}
|
||||
|
||||
export const ErrorWithErrorMessage = Template.bind({})
|
||||
ErrorWithErrorMessage.args = {
|
||||
error: mockError,
|
||||
severity: "error",
|
||||
}
|
||||
|
||||
export const WarningWithDismiss = Template.bind({})
|
||||
WarningWithDismiss.args = {
|
||||
text: "This is a warning",
|
||||
dismissible: true,
|
||||
severity: "warning",
|
||||
}
|
||||
|
||||
export const ErrorWithDismiss = Template.bind({})
|
||||
ErrorWithDismiss.args = {
|
||||
error: mockError,
|
||||
dismissible: true,
|
||||
severity: "error",
|
||||
}
|
||||
|
||||
export const WarningWithAction = Template.bind({})
|
||||
WarningWithAction.args = {
|
||||
text: "This is a warning",
|
||||
actions: [ExampleAction],
|
||||
severity: "warning",
|
||||
}
|
||||
|
||||
export const ErrorWithAction = Template.bind({})
|
||||
ErrorWithAction.args = {
|
||||
error: mockError,
|
||||
actions: [ExampleAction],
|
||||
severity: "error",
|
||||
}
|
||||
|
||||
export const WarningWithActionAndDismiss = Template.bind({})
|
||||
WarningWithActionAndDismiss.args = {
|
||||
text: "This is a warning",
|
||||
actions: [ExampleAction],
|
||||
dismissible: true,
|
||||
severity: "warning",
|
||||
}
|
||||
|
||||
export const ErrorWithActionAndDismiss = Template.bind({})
|
||||
ErrorWithActionAndDismiss.args = {
|
||||
error: mockError,
|
||||
actions: [ExampleAction],
|
||||
dismissible: true,
|
||||
severity: "error",
|
||||
}
|
||||
|
||||
export const ErrorWithRetry = Template.bind({})
|
||||
ErrorWithRetry.args = {
|
||||
error: mockError,
|
||||
retry: () => null,
|
||||
dismissible: true,
|
||||
severity: "error",
|
||||
}
|
||||
|
||||
export const ErrorWithActionRetryAndDismiss = Template.bind({})
|
||||
ErrorWithActionRetryAndDismiss.args = {
|
||||
error: mockError,
|
||||
actions: [ExampleAction],
|
||||
retry: () => null,
|
||||
dismissible: true,
|
||||
severity: "error",
|
||||
}
|
||||
|
||||
export const ErrorAsWarning = Template.bind({})
|
||||
ErrorAsWarning.args = {
|
||||
error: mockError,
|
||||
severity: "warning",
|
||||
}
|
||||
|
||||
const WithChildren: Story<AlertBannerProps> = (args) => (
|
||||
<AlertBanner {...args}>
|
||||
<div>
|
||||
This is a message with a <Link href="#">link</Link>
|
||||
</div>
|
||||
</AlertBanner>
|
||||
)
|
||||
|
||||
export const InfoWithChildContent = WithChildren.bind({})
|
||||
InfoWithChildContent.args = {
|
||||
severity: "info",
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import { useState, FC, Children } from "react"
|
||||
import Collapse from "@mui/material/Collapse"
|
||||
import { Stack } from "components/Stack/Stack"
|
||||
import { makeStyles } from "@mui/styles"
|
||||
import { colors } from "theme/colors"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { getErrorDetail, getErrorMessage } from "api/errors"
|
||||
import { Expander } from "components/Expander/Expander"
|
||||
import { Severity, AlertBannerProps } from "./alertTypes"
|
||||
import { severityConstants } from "./severityConstants"
|
||||
import { AlertBannerCtas } from "./AlertBannerCtas"
|
||||
import { Theme } from "@mui/material/styles"
|
||||
|
||||
/**
|
||||
* @param children: the children to be displayed in the alert
|
||||
* @param severity: the level of alert severity (see ./severityTypes.ts)
|
||||
* @param text: default text to be displayed to the user; useful for warnings or as a fallback error message
|
||||
* @param error: should be passed in if the severity is 'Error'; warnings can use 'text' instead
|
||||
* @param actions: an array of CTAs passed in by the consumer
|
||||
* @param retry: a handler to retry the action that spawned the error
|
||||
* @param dismissible: determines whether or not the banner should have a `Dismiss` CTA
|
||||
* @param onDismiss: a handler that is called when the `Dismiss` CTA is clicked, after the animation has finished
|
||||
*/
|
||||
export const AlertBanner: FC<React.PropsWithChildren<AlertBannerProps>> = ({
|
||||
children,
|
||||
severity,
|
||||
text,
|
||||
error,
|
||||
actions = [],
|
||||
retry,
|
||||
dismissible = false,
|
||||
onDismiss,
|
||||
}) => {
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
const [open, setOpen] = useState(true)
|
||||
|
||||
// Set a fallback message if no text or children are provided.
|
||||
const defaultMessage =
|
||||
text ??
|
||||
(Children.count(children) === 0
|
||||
? t("warningsAndErrors.somethingWentWrong")
|
||||
: "")
|
||||
|
||||
// if an error is passed in, display that error, otherwise
|
||||
// display the text passed in, e.g. warning text
|
||||
const alertMessage = getErrorMessage(error, defaultMessage)
|
||||
|
||||
// if we have an error, check if there's detail to display
|
||||
const detail = error ? getErrorDetail(error) : undefined
|
||||
const classes = useStyles({ severity, hasDetail: Boolean(detail) })
|
||||
|
||||
const [showDetails, setShowDetails] = useState(false)
|
||||
|
||||
return (
|
||||
<Collapse in={open} onExited={() => onDismiss && onDismiss()}>
|
||||
<Stack
|
||||
className={classes.alertContainer}
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={0}
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={2}
|
||||
className={classes.fullWidth}
|
||||
>
|
||||
{severityConstants[severity].icon}
|
||||
<Stack spacing={0} className={classes.fullWidth}>
|
||||
{children}
|
||||
{alertMessage}
|
||||
{detail && (
|
||||
<Expander expanded={showDetails} setExpanded={setShowDetails}>
|
||||
<div>{detail}</div>
|
||||
</Expander>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<AlertBannerCtas
|
||||
actions={actions}
|
||||
dismissible={dismissible}
|
||||
retry={retry}
|
||||
setOpen={setOpen}
|
||||
/>
|
||||
</Stack>
|
||||
</Collapse>
|
||||
)
|
||||
}
|
||||
|
||||
interface StyleProps {
|
||||
severity: Severity
|
||||
hasDetail: boolean
|
||||
}
|
||||
|
||||
const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
|
||||
alertContainer: (props) => ({
|
||||
...theme.typography.body2,
|
||||
borderColor: severityConstants[props.severity].color,
|
||||
border: `1px solid ${colors.orange[7]}`,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
padding: theme.spacing(2),
|
||||
backgroundColor: `${colors.gray[16]}`,
|
||||
textAlign: "left",
|
||||
|
||||
"& > span": {
|
||||
paddingTop: theme.spacing(0.25),
|
||||
},
|
||||
|
||||
// targeting the alert icon rather than the expander icon
|
||||
"& svg:nth-child(2)": {
|
||||
marginTop: props.hasDetail ? theme.spacing(1) : "inherit",
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
}),
|
||||
|
||||
fullWidth: {
|
||||
width: "100%",
|
||||
},
|
||||
}))
|
||||
@@ -1,50 +0,0 @@
|
||||
import { FC } from "react"
|
||||
import { AlertBannerProps } from "./alertTypes"
|
||||
import { Stack } from "components/Stack/Stack"
|
||||
import Button from "@mui/material/Button"
|
||||
import RefreshIcon from "@mui/icons-material/Refresh"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
type AlertBannerCtasProps = Pick<
|
||||
AlertBannerProps,
|
||||
"actions" | "dismissible" | "retry"
|
||||
> & {
|
||||
setOpen: (arg0: boolean) => void
|
||||
}
|
||||
|
||||
export const AlertBannerCtas: FC<AlertBannerCtasProps> = ({
|
||||
actions = [],
|
||||
dismissible,
|
||||
retry,
|
||||
setOpen,
|
||||
}) => {
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
return (
|
||||
<Stack direction="row">
|
||||
{/* CTAs passed in by the consumer */}
|
||||
{actions.length > 0 &&
|
||||
actions.map((action) => <div key={String(action)}>{action}</div>)}
|
||||
|
||||
{/* retry CTA */}
|
||||
{retry && (
|
||||
<div>
|
||||
<Button size="small" onClick={retry} startIcon={<RefreshIcon />}>
|
||||
{t("ctas.retry")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* close CTA */}
|
||||
{dismissible && (
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => setOpen(false)}
|
||||
data-testid="dismiss-banner-btn"
|
||||
>
|
||||
{t("ctas.dismissCta")}
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { ApiError } from "api/errors"
|
||||
import { ReactElement } from "react"
|
||||
|
||||
export type Severity = "warning" | "error" | "info"
|
||||
|
||||
export interface AlertBannerProps {
|
||||
severity: Severity
|
||||
text?: JSX.Element | string
|
||||
error?: ApiError | Error | unknown
|
||||
actions?: ReactElement[]
|
||||
dismissible?: boolean
|
||||
onDismiss?: () => void
|
||||
retry?: () => void
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import ReportProblemOutlinedIcon from "@mui/icons-material/ReportProblemOutlined"
|
||||
import ErrorOutlineOutlinedIcon from "@mui/icons-material/ErrorOutlineOutlined"
|
||||
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"
|
||||
import { colors } from "theme/colors"
|
||||
import { Severity } from "./alertTypes"
|
||||
import { ReactElement } from "react"
|
||||
|
||||
export const severityConstants: Record<
|
||||
Severity,
|
||||
{ color: string; icon: ReactElement }
|
||||
> = {
|
||||
warning: {
|
||||
color: colors.orange[7],
|
||||
icon: (
|
||||
<ReportProblemOutlinedIcon
|
||||
style={{ color: colors.orange[7], fontSize: 16 }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
error: {
|
||||
color: colors.red[7],
|
||||
icon: (
|
||||
<ErrorOutlineOutlinedIcon
|
||||
style={{ color: colors.red[7], fontSize: 16 }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
info: {
|
||||
color: colors.blue[7],
|
||||
icon: <InfoOutlinedIcon style={{ color: colors.blue[7], fontSize: 16 }} />,
|
||||
},
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from "../../utils/formUtils"
|
||||
import { LoadingButton } from "../LoadingButton/LoadingButton"
|
||||
import { Stack } from "../Stack/Stack"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export interface AccountFormValues {
|
||||
username: string
|
||||
@@ -62,7 +62,7 @@ export const AccountForm: FC<React.PropsWithChildren<AccountFormProps>> = ({
|
||||
<form onSubmit={form.handleSubmit}>
|
||||
<Stack>
|
||||
{Boolean(updateProfileError) && (
|
||||
<AlertBanner severity="error" error={updateProfileError} />
|
||||
<ErrorAlert error={updateProfileError} />
|
||||
)}
|
||||
<TextField
|
||||
disabled
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as Yup from "yup"
|
||||
import { getFormHelpers } from "../../utils/formUtils"
|
||||
import { LoadingButton } from "../LoadingButton/LoadingButton"
|
||||
import { Stack } from "../Stack/Stack"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
interface SecurityFormValues {
|
||||
old_password: string
|
||||
@@ -73,7 +73,7 @@ export const SecurityForm: FC<SecurityFormProps> = ({
|
||||
<form onSubmit={form.handleSubmit}>
|
||||
<Stack>
|
||||
{Boolean(updateSecurityError) && (
|
||||
<AlertBanner severity="error" error={updateSecurityError} />
|
||||
<ErrorAlert error={updateSecurityError} />
|
||||
)}
|
||||
<TextField
|
||||
{...getFieldHelpers("old_password")}
|
||||
|
||||
@@ -9,7 +9,8 @@ import { OAuthSignInForm } from "./OAuthSignInForm"
|
||||
import { BuiltInAuthFormValues } from "./SignInForm.types"
|
||||
import Button from "@mui/material/Button"
|
||||
import EmailIcon from "@mui/icons-material/EmailOutlined"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Alert } from "components/Alert/Alert"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export const Language = {
|
||||
emailLabel: "Email",
|
||||
@@ -100,7 +101,7 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
|
||||
</h1>
|
||||
<Maybe condition={error !== undefined}>
|
||||
<div className={styles.error}>
|
||||
<AlertBanner severity="error" error={error} />
|
||||
<ErrorAlert error={error} />
|
||||
</div>
|
||||
</Maybe>
|
||||
<Maybe condition={passwordEnabled && showPasswordAuth}>
|
||||
@@ -126,10 +127,7 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
|
||||
</Maybe>
|
||||
|
||||
<Maybe condition={!passwordEnabled && !oAuthEnabled}>
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
text="No authentication methods configured!"
|
||||
/>
|
||||
<Alert severity="error">No authentication methods configured!</Alert>
|
||||
</Maybe>
|
||||
|
||||
<Maybe condition={passwordEnabled && !showPasswordAuth}>
|
||||
|
||||
@@ -7,7 +7,6 @@ import { Margins } from "components/Margins/Margins"
|
||||
import { Stack } from "components/Stack/Stack"
|
||||
import { Loader } from "components/Loader/Loader"
|
||||
import { TemplatePageHeader } from "./TemplatePageHeader"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import {
|
||||
checkAuthorization,
|
||||
getTemplateByName,
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
} from "api/api"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { AuthorizationRequest } from "api/typesGenerated"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
const templatePermissions = (
|
||||
templateId: string,
|
||||
@@ -75,7 +75,7 @@ export const TemplateLayout: FC<{ children?: JSX.Element }> = ({
|
||||
if (error) {
|
||||
return (
|
||||
<div className={styles.error}>
|
||||
<AlertBanner severity="error" error={error} />
|
||||
<ErrorAlert error={error} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
VariableValue,
|
||||
WorkspaceResource,
|
||||
} from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Alert } from "components/Alert/Alert"
|
||||
import { Avatar } from "components/Avatar/Avatar"
|
||||
import { AvatarData } from "components/AvatarData/AvatarData"
|
||||
import { bannerHeight } from "components/DeploymentBanner/DeploymentBannerView"
|
||||
@@ -206,7 +206,6 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
|
||||
|
||||
<Button
|
||||
title="Build template (Ctrl + Enter)"
|
||||
size="small"
|
||||
disabled={disablePreview}
|
||||
onClick={() => {
|
||||
triggerPreview()
|
||||
@@ -224,7 +223,6 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
|
||||
? "Something"
|
||||
: ""
|
||||
}
|
||||
size="small"
|
||||
disabled={dirty || disableUpdate}
|
||||
onClick={onPublish}
|
||||
>
|
||||
@@ -240,7 +238,6 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
|
||||
<div className={styles.sidebarActions}>
|
||||
<Tooltip title="Create File" placement="top">
|
||||
<IconButton
|
||||
size="small"
|
||||
aria-label="Create File"
|
||||
onClick={(event) => {
|
||||
setCreateFileOpen(true)
|
||||
@@ -377,10 +374,7 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
|
||||
}`}
|
||||
>
|
||||
{templateVersion.job.error && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
text={templateVersion.job.error}
|
||||
/>
|
||||
<Alert severity="error">{templateVersion.job.error}</Alert>
|
||||
)}
|
||||
|
||||
{buildLogs && buildLogs.length > 0 && (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FC } from "react"
|
||||
import * as TypesGen from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Alert } from "components/Alert/Alert"
|
||||
import { Maybe } from "components/Conditionals/Maybe"
|
||||
import Link from "@mui/material/Link"
|
||||
|
||||
@@ -18,16 +18,14 @@ export const TemplateVersionWarnings: FC<
|
||||
return (
|
||||
<Maybe condition={Boolean(warnings.includes("DEPRECATED_PARAMETERS"))}>
|
||||
<div data-testid="warning-deprecated-parameters">
|
||||
<AlertBanner severity="warning">
|
||||
<div>
|
||||
This template uses legacy parameters which will be deprecated in the
|
||||
next Coder release. Learn how to migrate in{" "}
|
||||
<Link href="https://coder.com/docs/v2/latest/templates/parameters#migration">
|
||||
our documentation
|
||||
</Link>
|
||||
.
|
||||
</div>
|
||||
</AlertBanner>
|
||||
<Alert severity="warning">
|
||||
This template uses legacy parameters which will be deprecated in the
|
||||
next Coder release. Learn how to migrate in{" "}
|
||||
<Link href="https://coder.com/docs/v2/latest/templates/parameters#migration">
|
||||
our documentation
|
||||
</Link>
|
||||
.
|
||||
</Alert>
|
||||
</div>
|
||||
</Maybe>
|
||||
)
|
||||
|
||||
@@ -73,7 +73,6 @@ export const VersionRow: React.FC<VersionRowProps> = ({
|
||||
) : (
|
||||
onPromoteClick && (
|
||||
<Button
|
||||
size="small"
|
||||
className={styles.promoteButton}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
|
||||
@@ -16,7 +16,7 @@ ExampleWithDismiss.args = {
|
||||
}
|
||||
|
||||
const ExampleAction = (
|
||||
<Button onClick={() => null} size="small">
|
||||
<Button onClick={() => null} size="small" variant="text">
|
||||
Button
|
||||
</Button>
|
||||
)
|
||||
|
||||
@@ -12,7 +12,7 @@ import { FC } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import * as TypesGen from "../../api/typesGenerated"
|
||||
import { AlertBanner } from "../AlertBanner/AlertBanner"
|
||||
import { Alert } from "../Alert/Alert"
|
||||
import { BuildsTable } from "../BuildsTable/BuildsTable"
|
||||
import { Margins } from "../Margins/Margins"
|
||||
import { Resources } from "../Resources/Resources"
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
PageHeaderSubtitle,
|
||||
} from "components/PageHeader/FullWidthPageHeader"
|
||||
import { TemplateVersionWarnings } from "components/TemplateVersionWarnings/TemplateVersionWarnings"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export enum WorkspaceErrors {
|
||||
GET_BUILDS_ERROR = "getBuildsError",
|
||||
@@ -106,8 +107,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
const { t } = useTranslation("workspacePage")
|
||||
|
||||
const buildError = Boolean(workspaceErrors[WorkspaceErrors.BUILD_ERROR]) && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
<ErrorAlert
|
||||
error={workspaceErrors[WorkspaceErrors.BUILD_ERROR]}
|
||||
dismissible
|
||||
/>
|
||||
@@ -116,8 +116,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
const cancellationError = Boolean(
|
||||
workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR],
|
||||
) && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
<ErrorAlert
|
||||
error={workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR]}
|
||||
dismissible
|
||||
/>
|
||||
@@ -193,7 +192,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
|
||||
{failedBuildLogs && (
|
||||
<Stack>
|
||||
<AlertBanner severity="error">
|
||||
<Alert severity="error">
|
||||
<Stack
|
||||
className={styles.fullWidth}
|
||||
direction="row"
|
||||
@@ -219,7 +218,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
</div>
|
||||
)}
|
||||
</Stack>
|
||||
</AlertBanner>
|
||||
</Alert>
|
||||
<WorkspaceBuildLogs logs={failedBuildLogs} />
|
||||
</Stack>
|
||||
)}
|
||||
@@ -251,8 +250,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
)}
|
||||
|
||||
{workspaceErrors[WorkspaceErrors.GET_BUILDS_ERROR] ? (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
<ErrorAlert
|
||||
error={workspaceErrors[WorkspaceErrors.GET_BUILDS_ERROR]}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -22,7 +22,6 @@ export const UpdateButton: FC<WorkspaceAction> = ({
|
||||
loading={loading}
|
||||
loadingIndicator="Updating..."
|
||||
loadingPosition="start"
|
||||
size="small"
|
||||
data-testid="workspace-update-button"
|
||||
startIcon={<CloudQueueIcon />}
|
||||
onClick={handleAction}
|
||||
@@ -35,7 +34,6 @@ export const UpdateButton: FC<WorkspaceAction> = ({
|
||||
export const StartButton: FC<WorkspaceAction> = ({ handleAction, loading }) => {
|
||||
return (
|
||||
<LoadingButton
|
||||
size="small"
|
||||
loading={loading}
|
||||
loadingIndicator="Starting..."
|
||||
loadingPosition="start"
|
||||
@@ -50,7 +48,6 @@ export const StartButton: FC<WorkspaceAction> = ({ handleAction, loading }) => {
|
||||
export const StopButton: FC<WorkspaceAction> = ({ handleAction, loading }) => {
|
||||
return (
|
||||
<LoadingButton
|
||||
size="small"
|
||||
loading={loading}
|
||||
loadingIndicator="Stopping..."
|
||||
loadingPosition="start"
|
||||
@@ -71,7 +68,6 @@ export const RestartButton: FC<WorkspaceAction> = ({
|
||||
loading={loading}
|
||||
loadingIndicator="Restarting..."
|
||||
loadingPosition="start"
|
||||
size="small"
|
||||
startIcon={<ReplayIcon />}
|
||||
onClick={handleAction}
|
||||
data-testid="workspace-restart-button"
|
||||
@@ -83,7 +79,7 @@ export const RestartButton: FC<WorkspaceAction> = ({
|
||||
|
||||
export const CancelButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
||||
return (
|
||||
<Button size="small" startIcon={<BlockIcon />} onClick={handleAction}>
|
||||
<Button startIcon={<BlockIcon />} onClick={handleAction}>
|
||||
Cancel
|
||||
</Button>
|
||||
)
|
||||
@@ -95,7 +91,7 @@ interface DisabledProps {
|
||||
|
||||
export const DisabledButton: FC<DisabledProps> = ({ label }) => {
|
||||
return (
|
||||
<Button size="small" startIcon={<BlockOutlined />} disabled>
|
||||
<Button startIcon={<BlockOutlined />} disabled>
|
||||
{label}
|
||||
</Button>
|
||||
)
|
||||
@@ -109,7 +105,6 @@ export const ActionLoadingButton: FC<LoadingProps> = ({ label }) => {
|
||||
return (
|
||||
<LoadingButton
|
||||
loading
|
||||
size="small"
|
||||
loadingPosition="start"
|
||||
loadingIndicator={label}
|
||||
// This icon can be anything
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Button from "@mui/material/Button"
|
||||
import { FC } from "react"
|
||||
import * as TypesGen from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Alert } from "components/Alert/Alert"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Maybe } from "components/Conditionals/Maybe"
|
||||
|
||||
@@ -16,18 +16,16 @@ export const WorkspaceDeletedBanner: FC<
|
||||
const { t } = useTranslation("workspacePage")
|
||||
|
||||
const NewWorkspaceButton = (
|
||||
<Button onClick={handleClick} size="small">
|
||||
<Button onClick={handleClick} size="small" variant="text">
|
||||
{t("ctas.createWorkspaceCta")}
|
||||
</Button>
|
||||
)
|
||||
|
||||
return (
|
||||
<Maybe condition={workspace.latest_build.status === "deleted"}>
|
||||
<AlertBanner
|
||||
text={t("warningsAndErrors.workspaceDeletedWarning")}
|
||||
actions={[NewWorkspaceButton]}
|
||||
severity="warning"
|
||||
/>
|
||||
<Alert severity="warning" actions={[NewWorkspaceButton]}>
|
||||
{t("warningsAndErrors.workspaceDeletedWarning")}
|
||||
</Alert>
|
||||
</Maybe>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useMachine } from "@xstate/react"
|
||||
import { isApiValidationError } from "api/errors"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Maybe } from "components/Conditionals/Maybe"
|
||||
import { useDashboard } from "components/Dashboard/DashboardProvider"
|
||||
import { FullPageHorizontalForm } from "components/FullPageForm/FullPageHorizontalForm"
|
||||
@@ -14,6 +13,7 @@ import { useNavigate, useSearchParams } from "react-router-dom"
|
||||
import { pageTitle } from "utils/page"
|
||||
import { createTemplateMachine } from "xServices/createTemplate/createTemplateXService"
|
||||
import { CreateTemplateForm } from "./CreateTemplateForm"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
const CreateTemplatePage: FC = () => {
|
||||
const { t } = useTranslation("createTemplatePage")
|
||||
@@ -64,7 +64,7 @@ const CreateTemplatePage: FC = () => {
|
||||
|
||||
<Stack spacing={6}>
|
||||
<Maybe condition={Boolean(error && !isApiValidationError(error))}>
|
||||
<AlertBanner error={error} severity="error" />
|
||||
<ErrorAlert error={error} />
|
||||
</Maybe>
|
||||
|
||||
{shouldDisplayForm && (
|
||||
|
||||
@@ -11,10 +11,10 @@ import { useMutation, useQuery } from "@tanstack/react-query"
|
||||
import { createToken, getTokenConfig } from "api/api"
|
||||
import { CreateTokenForm } from "./CreateTokenForm"
|
||||
import { NANO_HOUR, CreateTokenData } from "./utils"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog"
|
||||
import { CodeExample } from "components/CodeExample/CodeExample"
|
||||
import { makeStyles } from "@mui/styles"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
const initialValues: CreateTokenData = {
|
||||
name: "",
|
||||
@@ -87,9 +87,7 @@ export const CreateTokenPage: FC = () => {
|
||||
<Helmet>
|
||||
<title>{pageTitle(t("createToken.title"))}</title>
|
||||
</Helmet>
|
||||
{tokenFetchFailed && (
|
||||
<AlertBanner severity="error" error={tokenFetchError} />
|
||||
)}
|
||||
{tokenFetchFailed && <ErrorAlert error={tokenFetchError} />}
|
||||
<FullPageHorizontalForm
|
||||
title={t("createToken.title")}
|
||||
detail={t("createToken.detail")}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { FC, useEffect, useState } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { getFormHelpers, nameValidator, onChangeTrimmed } from "utils/formUtils"
|
||||
import * as Yup from "yup"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { FullPageHorizontalForm } from "components/FullPageForm/FullPageHorizontalForm"
|
||||
import { SelectedTemplate } from "./SelectedTemplate"
|
||||
import { Loader } from "components/Loader/Loader"
|
||||
@@ -29,6 +28,7 @@ import {
|
||||
ImmutableTemplateParametersSection,
|
||||
MutableTemplateParametersSection,
|
||||
} from "components/TemplateParameters/TemplateParameters"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export enum CreateWorkspaceErrors {
|
||||
GET_TEMPLATES_ERROR = "getTemplatesError",
|
||||
@@ -174,8 +174,7 @@ export const CreateWorkspacePageView: FC<
|
||||
CreateWorkspaceErrors.GET_TEMPLATES_ERROR
|
||||
],
|
||||
) && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
<ErrorAlert
|
||||
error={
|
||||
props.createWorkspaceErrors[
|
||||
CreateWorkspaceErrors.GET_TEMPLATES_ERROR
|
||||
@@ -188,8 +187,7 @@ export const CreateWorkspacePageView: FC<
|
||||
CreateWorkspaceErrors.GET_TEMPLATE_SCHEMA_ERROR
|
||||
],
|
||||
) && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
<ErrorAlert
|
||||
error={
|
||||
props.createWorkspaceErrors[
|
||||
CreateWorkspaceErrors.GET_TEMPLATE_SCHEMA_ERROR
|
||||
@@ -202,8 +200,7 @@ export const CreateWorkspacePageView: FC<
|
||||
CreateWorkspaceErrors.GET_TEMPLATE_GITAUTH_ERROR
|
||||
],
|
||||
) && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
<ErrorAlert
|
||||
error={
|
||||
props.createWorkspaceErrors[
|
||||
CreateWorkspaceErrors.GET_TEMPLATE_GITAUTH_ERROR
|
||||
@@ -219,8 +216,7 @@ export const CreateWorkspacePageView: FC<
|
||||
CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR
|
||||
],
|
||||
) && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
<ErrorAlert
|
||||
error={
|
||||
props.createWorkspaceErrors[
|
||||
CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DeploymentOption } from "api/types"
|
||||
import { DeploymentDAUsResponse } from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
import { DAUChart } from "components/DAUChart/DAUChart"
|
||||
import { Header } from "components/DeploySettingsLayout/Header"
|
||||
import OptionsTable from "components/DeploySettingsLayout/OptionsTable"
|
||||
@@ -26,7 +26,7 @@ export const GeneralSettingsPageView = ({
|
||||
/>
|
||||
<Stack spacing={4}>
|
||||
{Boolean(getDeploymentDAUsError) && (
|
||||
<AlertBanner error={getDeploymentDAUsError} severity="error" />
|
||||
<ErrorAlert error={getDeploymentDAUsError} />
|
||||
)}
|
||||
{deploymentDAUs && <DAUChart daus={deploymentDAUs} />}
|
||||
<OptionsTable
|
||||
|
||||
@@ -6,7 +6,7 @@ import TableContainer from "@mui/material/TableContainer"
|
||||
import TableHead from "@mui/material/TableHead"
|
||||
import TableRow from "@mui/material/TableRow"
|
||||
import { DeploymentValues, GitAuthConfig } from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Alert } from "components/Alert/Alert"
|
||||
import { EnterpriseBadge } from "components/DeploySettingsLayout/Badges"
|
||||
import { Header } from "components/DeploySettingsLayout/Header"
|
||||
|
||||
@@ -40,11 +40,9 @@ export const GitAuthSettingsPageView = ({
|
||||
/>
|
||||
|
||||
<div className={styles.description}>
|
||||
<AlertBanner
|
||||
severity="info"
|
||||
text="Integrating with multiple Git providers is an Enterprise feature."
|
||||
actions={[<EnterpriseBadge key="enterprise" />]}
|
||||
/>
|
||||
<Alert severity="info" actions={[<EnterpriseBadge key="enterprise" />]}>
|
||||
Integrating with multiple Git providers is an Enterprise feature.
|
||||
</Alert>
|
||||
</div>
|
||||
|
||||
<TableContainer>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import Button from "@mui/material/Button"
|
||||
import TextField from "@mui/material/TextField"
|
||||
import { makeStyles } from "@mui/styles"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Fieldset } from "components/DeploySettingsLayout/Fieldset"
|
||||
import { Header } from "components/DeploySettingsLayout/Header"
|
||||
import { FileUpload } from "components/FileUpload/FileUpload"
|
||||
@@ -11,6 +10,7 @@ import { Stack } from "components/Stack/Stack"
|
||||
import { DividerWithText } from "pages/DeploySettingsPage/LicensesSettingsPage/DividerWithText"
|
||||
import { FC } from "react"
|
||||
import { Link as RouterLink } from "react-router-dom"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
type AddNewLicenseProps = {
|
||||
onSaveLicenseKey: (license: string) => void
|
||||
@@ -54,7 +54,7 @@ export const AddNewLicensePageView: FC<AddNewLicenseProps> = ({
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Header
|
||||
title="Add a License"
|
||||
title="Add a license"
|
||||
description="Get access to high availability, RBAC, quotas, and more."
|
||||
/>
|
||||
<Button
|
||||
@@ -66,9 +66,7 @@ export const AddNewLicensePageView: FC<AddNewLicenseProps> = ({
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
{savingLicenseError && (
|
||||
<AlertBanner severity="error" error={savingLicenseError}></AlertBanner>
|
||||
)}
|
||||
{savingLicenseError && <ErrorAlert error={savingLicenseError} />}
|
||||
|
||||
<FileUpload
|
||||
isUploading={isUploading}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FC } from "react"
|
||||
import Confetti from "react-confetti"
|
||||
import { Link } from "react-router-dom"
|
||||
import useWindowSize from "react-use/lib/useWindowSize"
|
||||
import MuiLink from "@mui/material/Link"
|
||||
|
||||
type Props = {
|
||||
showConfetti: boolean
|
||||
@@ -59,7 +60,7 @@ const LicensesSettingsPageView: FC<Props> = ({
|
||||
to="/settings/deployment/licenses/add"
|
||||
startIcon={<AddIcon />}
|
||||
>
|
||||
Add a License
|
||||
Add a license
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
@@ -89,9 +90,12 @@ const LicensesSettingsPageView: FC<Props> = ({
|
||||
</span>
|
||||
<span className={styles.description}>
|
||||
You{"'"}re missing out on high availability, RBAC, quotas, and
|
||||
much more. Contact <a href="mailto:sales@coder.com">sales</a> or{" "}
|
||||
<a href="https://coder.com/trial">request a trial license</a> to
|
||||
get started.
|
||||
much more. Contact{" "}
|
||||
<MuiLink href="mailto:sales@coder.com">sales</MuiLink> or{" "}
|
||||
<MuiLink href="https://coder.com/trial">
|
||||
request a trial license
|
||||
</MuiLink>{" "}
|
||||
to get started.
|
||||
</span>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
@@ -52,7 +52,6 @@ export const GroupsPageView: FC<GroupsPageViewProps> = ({
|
||||
href="https://coder.com/docs/coder-oss/latest/enterprise"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
size="small"
|
||||
startIcon={<ArrowRightAltOutlined />}
|
||||
variant="contained"
|
||||
>
|
||||
|
||||
@@ -12,10 +12,10 @@ import { FC } from "react"
|
||||
import { StarterTemplateContext } from "xServices/starterTemplates/starterTemplateXService"
|
||||
import ViewCodeIcon from "@mui/icons-material/OpenInNewOutlined"
|
||||
import PlusIcon from "@mui/icons-material/AddOutlined"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Stack } from "components/Stack/Stack"
|
||||
import { Link } from "react-router-dom"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export interface StarterTemplatePageViewProps {
|
||||
context: StarterTemplateContext
|
||||
@@ -31,7 +31,7 @@ export const StarterTemplatePageView: FC<StarterTemplatePageViewProps> = ({
|
||||
if (context.error) {
|
||||
return (
|
||||
<Margins>
|
||||
<AlertBanner error={context.error} severity="error" />
|
||||
<ErrorAlert error={context.error} />
|
||||
</Margins>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { makeStyles } from "@mui/styles"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
import { Maybe } from "components/Conditionals/Maybe"
|
||||
import { Loader } from "components/Loader/Loader"
|
||||
import { Margins } from "components/Margins/Margins"
|
||||
@@ -57,7 +57,7 @@ export const StarterTemplatesPageView: FC<StarterTemplatesPageViewProps> = ({
|
||||
</PageHeader>
|
||||
|
||||
<Maybe condition={Boolean(context.error)}>
|
||||
<AlertBanner error={context.error} severity="error" />
|
||||
<ErrorAlert error={context.error} />
|
||||
</Maybe>
|
||||
|
||||
<Maybe condition={Boolean(!starterTemplatesByTag)}>
|
||||
|
||||
-1
@@ -43,7 +43,6 @@ export const TemplatePermissionsPage: FC<
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
startIcon={<ArrowRightAltOutlined />}
|
||||
variant="contained"
|
||||
>
|
||||
|
||||
+12
-18
@@ -3,14 +3,14 @@ import {
|
||||
TemplateVersion,
|
||||
TemplateVersionVariable,
|
||||
} from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Alert } from "components/Alert/Alert"
|
||||
import { Loader } from "components/Loader/Loader"
|
||||
import { ComponentProps, FC } from "react"
|
||||
import { TemplateVariablesForm } from "./TemplateVariablesForm"
|
||||
import { Stack } from "components/Stack/Stack"
|
||||
import { makeStyles } from "@mui/styles"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export interface TemplateVariablesPageViewProps {
|
||||
templateVersion?: TemplateVersion
|
||||
@@ -50,21 +50,15 @@ export const TemplateVariablesPageView: FC<TemplateVariablesPageViewProps> = ({
|
||||
<PageHeader className={classes.pageHeader}>
|
||||
<PageHeaderTitle>{t("title")}</PageHeaderTitle>
|
||||
</PageHeader>
|
||||
{Boolean(errors.getTemplateDataError) && (
|
||||
<Stack className={classes.errorContainer}>
|
||||
<AlertBanner severity="error" error={errors.getTemplateDataError} />
|
||||
</Stack>
|
||||
)}
|
||||
{Boolean(errors.updateTemplateError) && (
|
||||
<Stack className={classes.errorContainer}>
|
||||
<AlertBanner severity="error" error={errors.updateTemplateError} />
|
||||
</Stack>
|
||||
)}
|
||||
{Boolean(errors.jobError) && (
|
||||
<Stack className={classes.errorContainer}>
|
||||
<AlertBanner severity="error" text={errors.jobError} />
|
||||
</Stack>
|
||||
)}
|
||||
<div className={classes.errorContainer}>
|
||||
{Boolean(errors.getTemplateDataError) && (
|
||||
<ErrorAlert error={errors.getTemplateDataError} />
|
||||
)}
|
||||
{Boolean(errors.updateTemplateError) && (
|
||||
<ErrorAlert error={errors.updateTemplateError} />
|
||||
)}
|
||||
{Boolean(errors.jobError) && <ErrorAlert error={errors.jobError} />}
|
||||
</div>
|
||||
{isLoading && <Loader />}
|
||||
{templateVersion && templateVariables && templateVariables.length > 0 && (
|
||||
<TemplateVariablesForm
|
||||
@@ -78,7 +72,7 @@ export const TemplateVariablesPageView: FC<TemplateVariablesPageViewProps> = ({
|
||||
/>
|
||||
)}
|
||||
{templateVariables && templateVariables.length === 0 && (
|
||||
<AlertBanner severity="info" text={t("unusedVariablesNotice")} />
|
||||
<Alert severity="info">{t("unusedVariablesNotice")}</Alert>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import Button from "@mui/material/Button"
|
||||
import Link from "@mui/material/Link"
|
||||
import EditIcon from "@mui/icons-material/Edit"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Loader } from "components/Loader/Loader"
|
||||
import { Margins } from "components/Margins/Margins"
|
||||
import {
|
||||
@@ -18,6 +17,7 @@ import { useTranslation } from "react-i18next"
|
||||
import { Link as RouterLink } from "react-router-dom"
|
||||
import { createDayString } from "utils/createDayString"
|
||||
import { TemplateVersionMachineContext } from "xServices/templateVersion/templateVersionXService"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export interface TemplateVersionPageViewProps {
|
||||
/**
|
||||
@@ -57,7 +57,7 @@ export const TemplateVersionPageView: FC<TemplateVersionPageViewProps> = ({
|
||||
{!currentFiles && !error && <Loader />}
|
||||
|
||||
<Stack spacing={4}>
|
||||
{Boolean(error) && <AlertBanner severity="error" error={error} />}
|
||||
{Boolean(error) && <ErrorAlert error={error} />}
|
||||
{currentVersion && currentFiles && (
|
||||
<>
|
||||
<Stats>
|
||||
|
||||
@@ -8,7 +8,6 @@ import TableContainer from "@mui/material/TableContainer"
|
||||
import TableHead from "@mui/material/TableHead"
|
||||
import TableRow from "@mui/material/TableRow"
|
||||
import AddIcon from "@mui/icons-material/AddOutlined"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"
|
||||
import { Maybe } from "components/Conditionals/Maybe"
|
||||
import { FC } from "react"
|
||||
@@ -42,6 +41,7 @@ import { combineClasses } from "utils/combineClasses"
|
||||
import { colors } from "theme/colors"
|
||||
import ArrowForwardOutlined from "@mui/icons-material/ArrowForwardOutlined"
|
||||
import { Avatar } from "components/Avatar/Avatar"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export const Language = {
|
||||
developerCount: (activeCount: number): string => {
|
||||
@@ -193,7 +193,7 @@ export const TemplatesPageView: FC<
|
||||
|
||||
<ChooseOne>
|
||||
<Cond condition={Boolean(error)}>
|
||||
<AlertBanner severity="error" error={error} />
|
||||
<ErrorAlert error={error} />
|
||||
</Cond>
|
||||
|
||||
<Cond>
|
||||
|
||||
@@ -5,10 +5,6 @@ import { useAuth } from "components/AuthProvider/AuthProvider"
|
||||
import { useMe } from "hooks/useMe"
|
||||
import { usePermissions } from "hooks/usePermissions"
|
||||
|
||||
export const Language = {
|
||||
title: "Account",
|
||||
}
|
||||
|
||||
export const AccountPage: FC = () => {
|
||||
const [authState, authSend] = useAuth()
|
||||
const me = useMe()
|
||||
@@ -17,7 +13,7 @@ export const AccountPage: FC = () => {
|
||||
const canEditUsers = permissions && permissions.updateUsers
|
||||
|
||||
return (
|
||||
<Section title={Language.title} description="Update your account info">
|
||||
<Section title="Account" description="Update your account info">
|
||||
<AccountForm
|
||||
editable={Boolean(canEditUsers)}
|
||||
email={me.email}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { renderWithAuth } from "../../../testHelpers/renderHelpers"
|
||||
import { Language as SSHKeysPageLanguage, SSHKeysPage } from "./SSHKeysPage"
|
||||
import { Language as SSHKeysPageViewLanguage } from "./SSHKeysPageView"
|
||||
import { i18n } from "i18n"
|
||||
import { MockGitSSHKey } from "testHelpers/entities"
|
||||
import { MockGitSSHKey, mockApiError } from "testHelpers/entities"
|
||||
|
||||
const { t } = i18n
|
||||
|
||||
@@ -66,7 +66,11 @@ describe("SSH keys Page", () => {
|
||||
// Wait to the ssh be rendered on the screen
|
||||
await screen.findByText(MockGitSSHKey.public_key)
|
||||
|
||||
jest.spyOn(API, "regenerateUserSSHKey").mockRejectedValueOnce({})
|
||||
jest.spyOn(API, "regenerateUserSSHKey").mockRejectedValueOnce(
|
||||
mockApiError({
|
||||
message: "Error regenerating SSH key",
|
||||
}),
|
||||
)
|
||||
|
||||
// Click on the "Regenerate" button to display the confirm dialog
|
||||
const regenerateButton = screen.getByRole("button", {
|
||||
@@ -85,7 +89,7 @@ describe("SSH keys Page", () => {
|
||||
fireEvent.click(confirmButton)
|
||||
|
||||
// Check if the error message is displayed
|
||||
await screen.findByText(SSHKeysPageViewLanguage.errorRegenerateSSHKey)
|
||||
await screen.findByText("Error regenerating SSH key")
|
||||
|
||||
// Check if the API was called correctly
|
||||
expect(API.regenerateUserSSHKey).toBeCalledTimes(1)
|
||||
|
||||
@@ -3,13 +3,12 @@ import Box from "@mui/material/Box"
|
||||
import Button from "@mui/material/Button"
|
||||
import CircularProgress from "@mui/material/CircularProgress"
|
||||
import { GitSSHKey } from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { CodeExample } from "components/CodeExample/CodeExample"
|
||||
import { Stack } from "components/Stack/Stack"
|
||||
import { FC } from "react"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export const Language = {
|
||||
errorRegenerateSSHKey: "Error on regenerating the SSH Key",
|
||||
regenerateLabel: "Regenerate",
|
||||
}
|
||||
|
||||
@@ -46,16 +45,9 @@ export const SSHKeysPageView: FC<
|
||||
<Stack>
|
||||
{/* Regenerating the key is not an option if getSSHKey fails.
|
||||
Only one of the error messages will exist at a single time */}
|
||||
{Boolean(getSSHKeyError) && (
|
||||
<AlertBanner severity="error" error={getSSHKeyError} />
|
||||
)}
|
||||
{Boolean(getSSHKeyError) && <ErrorAlert error={getSSHKeyError} />}
|
||||
{Boolean(regenerateSSHKeyError) && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
error={regenerateSSHKeyError}
|
||||
text={Language.errorRegenerateSSHKey}
|
||||
dismissible
|
||||
/>
|
||||
<ErrorAlert error={regenerateSSHKeyError} dismissible />
|
||||
)}
|
||||
{hasLoaded && sshKey && (
|
||||
<>
|
||||
|
||||
@@ -12,11 +12,11 @@ import { TableLoader } from "components/TableLoader/TableLoader"
|
||||
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline"
|
||||
import dayjs from "dayjs"
|
||||
import { FC } from "react"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import IconButton from "@mui/material/IconButton/IconButton"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { APIKeyWithOwner } from "api/typesGenerated"
|
||||
import relativeTime from "dayjs/plugin/relativeTime"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
@@ -50,12 +50,8 @@ export const TokensPageView: FC<
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
{Boolean(getTokensError) && (
|
||||
<AlertBanner severity="error" error={getTokensError} />
|
||||
)}
|
||||
{Boolean(deleteTokenError) && (
|
||||
<AlertBanner severity="error" error={deleteTokenError} />
|
||||
)}
|
||||
{Boolean(getTokensError) && <ErrorAlert error={getTokensError} />}
|
||||
{Boolean(deleteTokenError) && <ErrorAlert error={deleteTokenError} />}
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
|
||||
@@ -9,10 +9,10 @@ import { Stack } from "components/Stack/Stack"
|
||||
import { TableEmpty } from "components/TableEmpty/TableEmpty"
|
||||
import { TableLoader } from "components/TableLoader/TableLoader"
|
||||
import { FC } from "react"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Region } from "api/typesGenerated"
|
||||
import { ProxyRow } from "./WorkspaceProxyRow"
|
||||
import { ProxyLatencyReport } from "contexts/useProxyLatency"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export interface WorkspaceProxyViewProps {
|
||||
proxies?: Region[]
|
||||
@@ -40,11 +40,9 @@ export const WorkspaceProxyView: FC<
|
||||
return (
|
||||
<Stack>
|
||||
{Boolean(getWorkspaceProxiesError) && (
|
||||
<AlertBanner severity="error" error={getWorkspaceProxiesError} />
|
||||
)}
|
||||
{Boolean(selectProxyError) && (
|
||||
<AlertBanner severity="error" error={selectProxyError} />
|
||||
<ErrorAlert error={getWorkspaceProxiesError} />
|
||||
)}
|
||||
{Boolean(selectProxyError) && <ErrorAlert error={selectProxyError} />}
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Box from "@mui/material/Box"
|
||||
import { WorkspaceBuild } from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Alert } from "components/Alert/Alert"
|
||||
|
||||
const Language = {
|
||||
stateMessage:
|
||||
@@ -18,22 +18,19 @@ export const WorkspaceBuildStateError: React.FC<
|
||||
build.workspace_owner_name + "/" + build.workspace_name
|
||||
} --orphan`
|
||||
return (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
text={
|
||||
<Box>
|
||||
{Language.stateMessage} A template admin may run{" "}
|
||||
<Box
|
||||
component="code"
|
||||
display="inline-block"
|
||||
width="fit-content"
|
||||
fontWeight={600}
|
||||
>
|
||||
`{orphanCommand}`
|
||||
</Box>{" "}
|
||||
to delete the workspace skipping resource destruction.
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
<Alert severity="error">
|
||||
<Box>
|
||||
{Language.stateMessage} A template admin may run{" "}
|
||||
<Box
|
||||
component="code"
|
||||
display="inline-block"
|
||||
width="fit-content"
|
||||
fontWeight={600}
|
||||
>
|
||||
`{orphanCommand}`
|
||||
</Box>{" "}
|
||||
to delete the workspace skipping resource destruction.
|
||||
</Box>
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useQuery } from "@tanstack/react-query"
|
||||
import { useMachine } from "@xstate/react"
|
||||
import { getWorkspaceBuildLogs } from "api/api"
|
||||
import { Workspace } from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"
|
||||
import { Loader } from "components/Loader/Loader"
|
||||
import { FC, useRef } from "react"
|
||||
@@ -12,6 +11,7 @@ import { quotaMachine } from "xServices/quotas/quotasXService"
|
||||
import { workspaceMachine } from "xServices/workspace/workspaceXService"
|
||||
import { WorkspaceReadyPage } from "./WorkspaceReadyPage"
|
||||
import { RequirePermission } from "components/RequirePermission/RequirePermission"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
const useFailedBuildLogs = (workspace: Workspace | undefined) => {
|
||||
const now = useRef(new Date())
|
||||
@@ -61,23 +61,18 @@ export const WorkspacePage: FC = () => {
|
||||
<Cond condition={workspaceState.matches("error")}>
|
||||
<div className={styles.error}>
|
||||
{Boolean(getWorkspaceError) && (
|
||||
<AlertBanner severity="error" error={getWorkspaceError} />
|
||||
<ErrorAlert error={getWorkspaceError} />
|
||||
)}
|
||||
{Boolean(getTemplateWarning) && (
|
||||
<AlertBanner severity="error" error={getTemplateWarning} />
|
||||
<ErrorAlert error={getTemplateWarning} />
|
||||
)}
|
||||
{Boolean(getTemplateParametersWarning) && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
error={getTemplateParametersWarning}
|
||||
/>
|
||||
<ErrorAlert error={getTemplateParametersWarning} />
|
||||
)}
|
||||
{Boolean(checkPermissionsError) && (
|
||||
<AlertBanner severity="error" error={checkPermissionsError} />
|
||||
)}
|
||||
{Boolean(getQuotaError) && (
|
||||
<AlertBanner severity="error" error={getQuotaError} />
|
||||
<ErrorAlert error={checkPermissionsError} />
|
||||
)}
|
||||
{Boolean(getQuotaError) && <ErrorAlert error={getQuotaError} />}
|
||||
</div>
|
||||
</Cond>
|
||||
<Cond
|
||||
|
||||
+4
-6
@@ -1,6 +1,6 @@
|
||||
import { makeStyles } from "@mui/styles"
|
||||
import { useMachine } from "@xstate/react"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Alert } from "components/Alert/Alert"
|
||||
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog"
|
||||
import { Loader } from "components/Loader/Loader"
|
||||
import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader"
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
formValuesToAutostartRequest,
|
||||
formValuesToTTLRequest,
|
||||
} from "./formToRequest"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
const getAutostart = (workspace: TypesGen.Workspace) =>
|
||||
scheduleToAutostart(workspace.autostart_schedule)
|
||||
@@ -75,13 +76,10 @@ export const WorkspaceSchedulePage: FC = () => {
|
||||
</PageHeader>
|
||||
{(scheduleState.hasTag("loading") || !template) && <Loader />}
|
||||
{scheduleState.matches("error") && (
|
||||
<AlertBanner
|
||||
severity="error"
|
||||
error={checkPermissionsError || getTemplateError}
|
||||
/>
|
||||
<ErrorAlert error={checkPermissionsError || getTemplateError} />
|
||||
)}
|
||||
{permissions && !permissions.updateWorkspace && (
|
||||
<AlertBanner severity="error" error={Error(t("forbiddenError"))} />
|
||||
<Alert severity="error">{t("forbiddenError")}</Alert>
|
||||
)}
|
||||
{template &&
|
||||
workspace &&
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Link from "@mui/material/Link"
|
||||
import { Workspace } from "api/typesGenerated"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Alert } from "components/Alert/Alert"
|
||||
import { Maybe } from "components/Conditionals/Maybe"
|
||||
import { PaginationWidgetBase } from "components/PaginationWidget/PaginationWidgetBase"
|
||||
import { FC } from "react"
|
||||
@@ -18,6 +18,7 @@ import { WorkspacesTable } from "components/WorkspacesTable/WorkspacesTable"
|
||||
import { workspaceFilterQuery } from "utils/filters"
|
||||
import { useLocalStorage } from "hooks"
|
||||
import difference from "lodash/difference"
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert"
|
||||
|
||||
export const Language = {
|
||||
pageTitle: "Workspaces",
|
||||
@@ -126,17 +127,10 @@ export const WorkspacesPageView: FC<
|
||||
|
||||
<Stack>
|
||||
<Maybe condition={Boolean(error)}>
|
||||
<AlertBanner
|
||||
error={error}
|
||||
severity={
|
||||
workspaces !== undefined && workspaces.length > 0
|
||||
? "warning"
|
||||
: "error"
|
||||
}
|
||||
/>
|
||||
<ErrorAlert error={error} />
|
||||
</Maybe>
|
||||
<Maybe condition={displayImpendingDeletionBanner}>
|
||||
<AlertBanner
|
||||
<Alert
|
||||
severity="info"
|
||||
onDismiss={() =>
|
||||
saveLocal(
|
||||
@@ -145,8 +139,9 @@ export const WorkspacesPageView: FC<
|
||||
)
|
||||
}
|
||||
dismissible
|
||||
text="You have workspaces that will be deleted soon."
|
||||
/>
|
||||
>
|
||||
You have workspaces that will be deleted soon.
|
||||
</Alert>
|
||||
</Maybe>
|
||||
|
||||
<SearchBarWithFilter
|
||||
|
||||
+39
-9
@@ -3,9 +3,9 @@ import { ThemeOptions, createTheme, Theme } from "@mui/material/styles"
|
||||
import { BODY_FONT_FAMILY, borderRadius } from "./constants"
|
||||
|
||||
// MUI does not have aligned heights for buttons and inputs so we have to "hack" it a little bit
|
||||
const BUTTON_LG_HEIGHT = 46
|
||||
const BUTTON_MD_HEIGHT = 40
|
||||
const BUTTON_SM_HEIGHT = 36
|
||||
const BUTTON_LG_HEIGHT = 42
|
||||
const BUTTON_MD_HEIGHT = 36
|
||||
const BUTTON_SM_HEIGHT = 30
|
||||
|
||||
export type PaletteIndex = keyof Theme["palette"]
|
||||
export type PaletteStatusIndex = Extract<
|
||||
@@ -40,7 +40,7 @@ export let dark = createTheme({
|
||||
divider: colors.gray[13],
|
||||
warning: {
|
||||
light: colors.orange[7],
|
||||
main: colors.orange[11],
|
||||
main: colors.orange[9],
|
||||
dark: colors.orange[15],
|
||||
},
|
||||
success: {
|
||||
@@ -48,13 +48,14 @@ export let dark = createTheme({
|
||||
dark: colors.green[15],
|
||||
},
|
||||
info: {
|
||||
light: colors.blue[9],
|
||||
main: colors.blue[11],
|
||||
light: colors.blue[7],
|
||||
main: colors.blue[9],
|
||||
dark: colors.blue[15],
|
||||
contrastText: colors.gray[4],
|
||||
},
|
||||
error: {
|
||||
main: colors.red[5],
|
||||
light: colors.red[6],
|
||||
main: colors.red[8],
|
||||
dark: colors.red[15],
|
||||
contrastText: colors.gray[4],
|
||||
},
|
||||
@@ -126,6 +127,7 @@ dark = createTheme(dark, {
|
||||
fontWeight: 500,
|
||||
height: BUTTON_MD_HEIGHT,
|
||||
padding: theme.spacing(1, 2),
|
||||
|
||||
whiteSpace: "nowrap",
|
||||
":focus-visible": {
|
||||
outline: `2px solid ${theme.palette.primary.main}`,
|
||||
@@ -164,12 +166,12 @@ dark = createTheme(dark, {
|
||||
},
|
||||
iconSizeMedium: {
|
||||
"& > .MuiSvgIcon-root": {
|
||||
fontSize: 16,
|
||||
fontSize: 14,
|
||||
},
|
||||
},
|
||||
iconSizeSmall: {
|
||||
"& > .MuiSvgIcon-root": {
|
||||
fontSize: 14,
|
||||
fontSize: 13,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -396,5 +398,33 @@ dark = createTheme(dark, {
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAlert: {
|
||||
defaultProps: {
|
||||
variant: "outlined",
|
||||
},
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
background: theme.palette.background.paper,
|
||||
}),
|
||||
action: {
|
||||
paddingTop: 2, // Idk why it is not aligned as expected
|
||||
},
|
||||
icon: {
|
||||
fontSize: 16,
|
||||
marginTop: "4px", // The size of text is 24 so (24 - 16)/2 = 4
|
||||
},
|
||||
message: ({ theme }) => ({
|
||||
color: theme.palette.text.primary,
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiAlertTitle: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontSize: "inherit",
|
||||
marginBottom: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ThemeOptions)
|
||||
|
||||
Reference in New Issue
Block a user