build(deps): update mui monorepo to v5.8.4 (major) (#3215)

pull/3563/head^2
James Elliott 2022-06-21 10:35:30 +10:00 committed by GitHub
parent 0a9dd4727d
commit 841e495dca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1180 additions and 533 deletions

View File

@ -17,13 +17,16 @@
}
},
"dependencies": {
"@emotion/cache": "11.9.3",
"@emotion/react": "11.9.3",
"@emotion/styled": "11.9.3",
"@fortawesome/fontawesome-svg-core": "6.1.1",
"@fortawesome/free-regular-svg-icons": "6.1.1",
"@fortawesome/free-solid-svg-icons": "6.1.1",
"@fortawesome/react-fontawesome": "0.1.18",
"@material-ui/core": "4.12.4",
"@material-ui/icons": "4.11.3",
"@material-ui/styles": "4.11.5",
"@mui/icons-material": "5.8.4",
"@mui/material": "5.8.4",
"@mui/styles": "5.8.4",
"axios": "0.27.2",
"classnames": "2.3.1",
"i18next": "21.8.10",
@ -151,7 +154,7 @@
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0",
"@vitejs/plugin-react": "1.3.2",
"esbuild": "0.14.46",
"esbuild": "0.14.17",
"esbuild-jest": "0.5.0",
"eslint": "8.18.0",
"eslint-config-prettier": "8.5.0",

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,9 @@
import React, { useState, useEffect, Suspense } from "react";
import createCache from "@emotion/cache";
import { CacheProvider } from "@emotion/react";
import { config as faConfig } from "@fortawesome/fontawesome-svg-core";
import { CssBaseline, ThemeProvider } from "@material-ui/core";
import { CssBaseline, ThemeProvider } from "@mui/material";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import NotificationBar from "@components/NotificationBar";
@ -51,9 +53,20 @@ function Theme() {
}
}
const App: React.FC = () => {
export interface Props {
nonce?: string;
}
const App: React.FC<Props> = (props: Props) => {
const [notification, setNotification] = useState(null as Notification | null);
const [theme, setTheme] = useState(Theme());
const cache = createCache({
key: "authelia",
nonce: props.nonce,
prepend: true,
});
useEffect(() => {
if (getTheme() === "auto") {
const query = window.matchMedia("(prefers-color-scheme: dark)");
@ -66,35 +79,37 @@ const App: React.FC = () => {
}
}, []);
return (
<ThemeProvider theme={theme}>
<Suspense fallback={<BaseLoadingPage message={"Loading"} />}>
<CssBaseline />
<NotificationsContext.Provider value={{ notification, setNotification }}>
<Router basename={getBasePath()}>
<NotificationBar onClose={() => setNotification(null)} />
<Routes>
<Route path={ResetPasswordStep1Route} element={<ResetPasswordStep1 />} />
<Route path={ResetPasswordStep2Route} element={<ResetPasswordStep2 />} />
<Route path={RegisterWebauthnRoute} element={<RegisterWebauthn />} />
<Route path={RegisterOneTimePasswordRoute} element={<RegisterOneTimePassword />} />
<Route path={LogoutRoute} element={<SignOut />} />
<Route path={ConsentRoute} element={<ConsentView />} />
<Route
path={`${IndexRoute}*`}
element={
<LoginPortal
duoSelfEnrollment={getDuoSelfEnrollment()}
rememberMe={getRememberMe()}
resetPassword={getResetPassword()}
resetPasswordCustomURL={getResetPasswordCustomURL()}
/>
}
/>
</Routes>
</Router>
</NotificationsContext.Provider>
</Suspense>
</ThemeProvider>
<CacheProvider value={cache}>
<ThemeProvider theme={theme}>
<Suspense fallback={<BaseLoadingPage message={"Loading"} />}>
<CssBaseline />
<NotificationsContext.Provider value={{ notification, setNotification }}>
<Router basename={getBasePath()}>
<NotificationBar onClose={() => setNotification(null)} />
<Routes>
<Route path={ResetPasswordStep1Route} element={<ResetPasswordStep1 />} />
<Route path={ResetPasswordStep2Route} element={<ResetPasswordStep2 />} />
<Route path={RegisterWebauthnRoute} element={<RegisterWebauthn />} />
<Route path={RegisterOneTimePasswordRoute} element={<RegisterOneTimePassword />} />
<Route path={LogoutRoute} element={<SignOut />} />
<Route path={ConsentRoute} element={<ConsentView />} />
<Route
path={`${IndexRoute}*`}
element={
<LoginPortal
duoSelfEnrollment={getDuoSelfEnrollment()}
rememberMe={getRememberMe()}
resetPassword={getResetPassword()}
resetPasswordCustomURL={getResetPasswordCustomURL()}
/>
}
/>
</Routes>
</Router>
</NotificationsContext.Provider>
</Suspense>
</ThemeProvider>
</CacheProvider>
);
};

View File

@ -1,6 +1,7 @@
import React from "react";
import { Link } from "@material-ui/core";
import { Box, Link, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import AppleStore from "@assets/images/applestore-badge.svg";
import GooglePlay from "@assets/images/googleplay-badge.svg";
@ -17,17 +18,21 @@ export interface Props {
const AppStoreBadges = function (props: Props) {
const target = props.targetBlank ? "_blank" : undefined;
const width = props.iconSize;
const styles = makeStyles((theme: Theme) => ({
badge: {
width: props.iconSize,
},
}))();
return (
<div className={props.className}>
<Link href={props.googlePlayLink} target={target}>
<img src={GooglePlay} alt="google play" style={{ width }} />
<Box className={props.className}>
<Link href={props.googlePlayLink} target={target} underline="hover">
<img src={GooglePlay} alt="google play" className={styles.badge} />
</Link>
<Link href={props.appleStoreLink} target={target}>
<img src={AppleStore} alt="apple store" style={{ width }} />
<Link href={props.appleStoreLink} target={target} underline="hover">
<img src={AppleStore} alt="apple store" className={styles.badge} />
</Link>
</div>
</Box>
);
};

View File

@ -1,15 +0,0 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import ColoredSnackbarContent from "@components/ColoredSnackbarContent";
it("renders without crashing", () => {
render(<ColoredSnackbarContent level="success" message="" />);
expect(screen.getByRole("alert")).toHaveTextContent("");
});
it("should contain the message", () => {
render(<ColoredSnackbarContent level="success" message="this is a success" />);
expect(screen.getByRole("alert")).toHaveTextContent("this is a success");
});

View File

@ -1,73 +0,0 @@
import React from "react";
import { makeStyles, SnackbarContent } from "@material-ui/core";
import { amber, green } from "@material-ui/core/colors";
import { SnackbarContentProps } from "@material-ui/core/SnackbarContent";
import CheckCircleIcon from "@material-ui/icons/CheckCircle";
import ErrorIcon from "@material-ui/icons/Error";
import InfoIcon from "@material-ui/icons/Info";
import WarningIcon from "@material-ui/icons/Warning";
import classnames from "classnames";
const variantIcon = {
success: CheckCircleIcon,
warning: WarningIcon,
error: ErrorIcon,
info: InfoIcon,
};
export type Level = keyof typeof variantIcon;
export interface Props extends SnackbarContentProps {
className?: string;
level: Level;
message: string;
}
const ColoredSnackbarContent = function (props: Props) {
const classes = useStyles();
const Icon = variantIcon[props.level];
const { className, variant, message, ...others } = props;
return (
<SnackbarContent
className={classnames(classes[props.level], className)}
message={
<span className={classes.message}>
<Icon className={classnames(classes.icon, classes.iconVariant)} />
{message}
</span>
}
{...others}
/>
);
};
export default ColoredSnackbarContent;
const useStyles = makeStyles((theme) => ({
success: {
backgroundColor: green[600],
},
error: {
backgroundColor: theme.palette.error.dark,
},
info: {
backgroundColor: theme.palette.primary.main,
},
warning: {
backgroundColor: amber[700],
},
icon: {
fontSize: 20,
},
iconVariant: {
opacity: 0.9,
marginRight: theme.spacing(1),
},
message: {
display: "flex",
alignItems: "center",
},
}));

View File

@ -1,9 +1,15 @@
import React from "react";
import { createTheme } from "@mui/material/styles";
import { ThemeProvider } from "@mui/styles";
import { render } from "@testing-library/react";
import FixedTextField from "@components/FixedTextField";
it("renders without crashing", () => {
render(<FixedTextField />);
render(
<ThemeProvider theme={createTheme()}>
<FixedTextField />
</ThemeProvider>,
);
});

View File

@ -1,7 +1,8 @@
import React from "react";
import { makeStyles } from "@material-ui/core";
import TextField, { TextFieldProps } from "@material-ui/core/TextField";
import { Theme } from "@mui/material/styles";
import TextField, { TextFieldProps } from "@mui/material/TextField";
import makeStyles from "@mui/styles/makeStyles";
/**
* This component fixes outlined TextField
@ -10,16 +11,16 @@ import TextField, { TextFieldProps } from "@material-ui/core/TextField";
* @param props the TextField props
*/
const FixedTextField = function (props: TextFieldProps) {
const style = useStyles();
const styles = useStyles();
return (
<TextField
{...props}
InputLabelProps={{
classes: {
root: style.label,
root: styles.label,
},
}}
inputProps={{ autoCapitalize: props.autoCapitalize }}
>
{props.children}
</TextField>
@ -28,7 +29,7 @@ const FixedTextField = function (props: TextFieldProps) {
export default FixedTextField;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
label: {
backgroundColor: theme.palette.background.default,
paddingLeft: theme.spacing(0.1),

View File

@ -1,13 +1,23 @@
import React from "react";
import { createTheme } from "@mui/material/styles";
import { ThemeProvider } from "@mui/styles";
import { render } from "@testing-library/react";
import LinearProgressBar from "@components/LinearProgressBar";
it("renders without crashing", () => {
render(<LinearProgressBar value={40} />);
render(
<ThemeProvider theme={createTheme()}>
<LinearProgressBar value={40} />)
</ThemeProvider>,
);
});
it("renders adjusted height without crashing", () => {
render(<LinearProgressBar value={40} height={2} />);
render(
<ThemeProvider theme={createTheme()}>
<LinearProgressBar value={40} height={2} />
</ThemeProvider>,
);
});

View File

@ -1,17 +1,16 @@
import React from "react";
import { makeStyles, LinearProgress } from "@material-ui/core";
import { CSSProperties } from "@material-ui/styles";
import { LinearProgress, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
export interface Props {
value: number;
height?: number;
height?: string | number;
className?: string;
style?: CSSProperties;
}
const LinearProgressBar = function (props: Props) {
const style = makeStyles((theme) => ({
const styles = makeStyles((theme: Theme) => ({
progressRoot: {
height: props.height ? props.height : theme.spacing(),
},
@ -19,13 +18,13 @@ const LinearProgressBar = function (props: Props) {
transition: "transform .2s linear",
},
}))();
return (
<LinearProgress
style={props.style as React.CSSProperties}
variant="determinate"
classes={{
root: style.progressRoot,
bar1Determinate: style.transition,
root: styles.progressRoot,
bar1Determinate: styles.transition,
}}
value={props.value}
className={props.className}

View File

@ -1,8 +1,7 @@
import React, { useState, useEffect } from "react";
import { Snackbar } from "@material-ui/core";
import { Alert, Slide, SlideProps, Snackbar } from "@mui/material";
import ColoredSnackbarContent from "@components/ColoredSnackbarContent";
import { useNotifications } from "@hooks/NotificationsContext";
import { Notification } from "@models/Notifications";
@ -10,12 +9,18 @@ export interface Props {
onClose: () => void;
}
type NotificationBarTransitionProps = Omit<SlideProps, "direction">;
function NotificationBarTransition(props: NotificationBarTransitionProps) {
return <Slide {...props} direction={"left"} />;
}
const NotificationBar = function (props: Props) {
const [tmpNotification, setTmpNotification] = useState(null as Notification | null);
const { notification } = useNotifications();
useEffect(() => {
if (notification && notification !== null) {
if (notification) {
setTmpNotification(notification);
}
}, [notification, setTmpNotification]);
@ -28,15 +33,18 @@ const NotificationBar = function (props: Props) {
anchorOrigin={{ vertical: "top", horizontal: "right" }}
autoHideDuration={tmpNotification ? tmpNotification.timeout * 1000 : 10000}
onClose={props.onClose}
TransitionComponent={NotificationBarTransition}
TransitionProps={{
onExited: () => setTmpNotification(null),
}}
>
<ColoredSnackbarContent
className="notification"
level={tmpNotification ? tmpNotification.level : "info"}
message={tmpNotification ? tmpNotification.message : ""}
/>
{tmpNotification ? (
<Alert severity={tmpNotification.level} variant={"filled"} elevation={6} className={"notification"}>
{tmpNotification.message}
</Alert>
) : (
<Alert severity={"success"} elevation={6} variant={"filled"} className={"notification"} />
)}
</Snackbar>
);
};

View File

@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import { makeStyles } from "@material-ui/core";
import { Box, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames";
import { useTranslation } from "react-i18next";
import zxcvbn from "zxcvbn";
@ -13,20 +14,12 @@ export interface Props {
}
const PasswordMeter = function (props: Props) {
const { t: translate } = useTranslation();
const [progressColor] = useState(["#D32F2F", "#FF5722", "#FFEB3B", "#AFB42B", "#62D32F"]);
const [passwordScore, setPasswordScore] = useState(0);
const [maxScores, setMaxScores] = useState(0);
const [feedback, setFeedback] = useState("");
const { t: translate } = useTranslation();
const style = makeStyles((theme) => ({
progressBar: {
height: "5px",
marginTop: "2px",
backgroundColor: "red",
width: "50%",
transition: "width .5s linear",
},
}))();
useEffect(() => {
const password = props.value;
@ -106,17 +99,23 @@ const PasswordMeter = function (props: Props) {
}
}, [props, translate]);
const styles = makeStyles((theme: Theme) => ({
progressBar: {
height: "5px",
marginTop: "2px",
backgroundColor: progressColor[passwordScore],
width: `${(passwordScore + 1) * (100 / maxScores)}%`,
transition: "width .5s linear",
},
progressContainer: {
width: "100%",
},
}))();
return (
<div style={{ width: "100%" }}>
<div
title={feedback}
className={classnames(style.progressBar)}
style={{
width: `${(passwordScore + 1) * (100 / maxScores)}%`,
backgroundColor: progressColor[passwordScore],
}}
/>
</div>
<Box className={styles.progressContainer}>
<Box title={feedback} className={classnames(styles.progressBar)} />
</Box>
);
};

View File

@ -1,32 +1,25 @@
import React, { Fragment } from "react";
import { Tooltip, Typography } from "@material-ui/core";
import { Variant } from "@material-ui/core/styles/createTypography";
import { CSSProperties } from "@material-ui/styles";
import { Tooltip, Typography } from "@mui/material";
import { Variant } from "@mui/material/styles/createTypography";
export interface Props {
variant: Variant;
value?: string;
style?: CSSProperties;
tooltip?: string;
tooltipStyle?: CSSProperties;
}
export default function TypographyWithTooltip(props: Props): JSX.Element {
return (
<Fragment>
{props.tooltip ? (
<Tooltip title={props.tooltip} style={props.tooltipStyle}>
<Typography variant={props.variant} style={props.style}>
{props.value}
</Typography>
<Tooltip title={props.tooltip}>
<Typography variant={props.variant}>{props.value}</Typography>
</Tooltip>
) : (
<Typography variant={props.variant} style={props.style}>
{props.value}
</Typography>
<Typography variant={props.variant}>{props.value}</Typography>
)}
</Fragment>
);

View File

@ -1,6 +1,7 @@
import { createContext, useContext, useRef } from "react";
import { Level } from "@components/ColoredSnackbarContent";
import { AlertColor } from "@mui/material";
import { Notification } from "@models/Notifications";
const defaultOptions = {
@ -19,7 +20,7 @@ export default NotificationsContext;
export function useNotifications() {
let useNotificationsProps = useContext(NotificationsContext);
const notificationBuilder = (level: Level) => {
const notificationBuilder = (level: AlertColor) => {
return (message: string, timeout?: number) => {
useNotificationsProps.setNotification({
level,

View File

@ -7,8 +7,9 @@ import App from "@root/App";
import * as serviceWorker from "@root/serviceWorker";
import "@i18n/index.ts";
const nonce = document.head.querySelector("[property=csp-nonce][content]")?.getAttribute("content") || undefined;
const root = createRoot(document.getElementById("root")!);
root.render(<App />);
root.render(<App nonce={nonce} />);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.

View File

@ -1,7 +1,8 @@
import React, { ReactNode, useEffect } from "react";
import { Grid, makeStyles, Container, Link } from "@material-ui/core";
import { grey } from "@material-ui/core/colors";
import { Grid, Container, Link, Theme } from "@mui/material";
import { grey } from "@mui/material/colors";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next";
import { ReactComponent as UserSvg } from "@assets/images/user.svg";
@ -18,20 +19,22 @@ export interface Props {
showBrand?: boolean;
}
const url = "https://www.authelia.com";
const LoginLayout = function (props: Props) {
const style = useStyles();
const styles = useStyles();
const logo = getLogoOverride() ? (
<img src="./static/media/logo.png" alt="Logo" className={style.icon} />
<img src="./static/media/logo.png" alt="Logo" className={styles.icon} />
) : (
<UserSvg className={style.icon} />
<UserSvg className={styles.icon} />
);
const { t: translate } = useTranslation();
useEffect(() => {
document.title = `${translate("Login")} - Authelia`;
}, [translate]);
return (
<Grid id={props.id} className={style.root} container spacing={0} alignItems="center" justifyContent="center">
<Container maxWidth="xs" className={style.rootContainer}>
<Grid id={props.id} className={styles.root} container spacing={0} alignItems="center" justifyContent="center">
<Container maxWidth="xs" className={styles.rootContainer}>
<Grid container>
<Grid item xs={12}>
{logo}
@ -50,16 +53,12 @@ const LoginLayout = function (props: Props) {
/>
</Grid>
) : null}
<Grid item xs={12} className={style.body}>
<Grid item xs={12} className={styles.body}>
{props.children}
</Grid>
{props.showBrand ? (
<Grid item xs={12}>
<Link
href="https://github.com/authelia/authelia"
target="_blank"
className={style.poweredBy}
>
<Link href={url} target="_blank" underline="hover" className={styles.poweredBy}>
{translate("Powered by")} Authelia
</Link>
</Grid>
@ -72,7 +71,7 @@ const LoginLayout = function (props: Props) {
export default LoginLayout;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
root: {
minHeight: "90vh",
textAlign: "center",

View File

@ -1,7 +1,7 @@
import { Level } from "@components/ColoredSnackbarContent";
import { AlertColor } from "@mui/material";
export interface Notification {
message: string;
level: Level;
level: AlertColor;
timeout: number;
}

View File

@ -1,4 +1,4 @@
import { createTheme } from "@material-ui/core/styles";
import { createTheme } from "@mui/material/styles";
const Dark = createTheme({
custom: {
@ -6,10 +6,81 @@ const Dark = createTheme({
loadingBar: "#fff",
},
palette: {
type: "dark",
mode: "dark",
primary: {
main: "#1976d2",
},
secondary: {
light: "#ff4081",
main: "#f50057",
dark: "#c51162",
contrastText: "#ffffff",
},
error: {
light: "#e57373",
main: "#f44336",
dark: "#d32f2f",
contrastText: "#ffffff",
},
warning: {
light: "#ffb74d",
main: "#ff9800",
dark: "#f57c00",
contrastText: "rgba(0, 0, 0, 0.87)",
},
info: {
light: "#64b5f6",
main: "#2196f3",
dark: "#1976d2",
contrastText: "#ffffff",
},
success: {
light: "#81c784",
main: "#4caf50",
dark: "#388e3c",
contrastText: "rgba(0, 0, 0, 0.87)",
},
grey: {
"50": "#fafafa",
"100": "#f5f5f5",
"200": "#eeeeee",
"300": "#e0e0e0",
"400": "#bdbdbd",
"500": "#9e9e9e",
"600": "#757575",
"700": "#616161",
"800": "#424242",
"900": "#212121",
A100: "#d5d5d5",
A200: "#aaaaaa",
A400: "#303030",
A700: "#616161",
},
contrastThreshold: 3,
tonalOffset: 0.2,
text: {
primary: "#fff",
secondary: "rgba(255, 255, 255, 0.7)",
disabled: "rgba(255, 255, 255, 0.5)",
},
divider: "rgba(255, 255, 255, 0.12)",
background: {
paper: "#424242",
default: "#303030",
},
action: {
active: "#fff",
hover: "rgba(255, 255, 255, 0.08)",
hoverOpacity: 0.08,
selected: "rgba(255, 255, 255, 0.16)",
selectedOpacity: 0.16,
disabled: "rgba(255, 255, 255, 0.3)",
disabledBackground: "rgba(255, 255, 255, 0.12)",
disabledOpacity: 0.38,
focus: "rgba(255, 255, 255, 0.12)",
focusOpacity: 0.12,
activatedOpacity: 0.24,
},
},
});

View File

@ -1,4 +1,4 @@
import { createTheme } from "@material-ui/core/styles";
import { createTheme } from "@mui/material/styles";
const Grey = createTheme({
custom: {
@ -6,51 +6,129 @@ const Grey = createTheme({
loadingBar: "#929aa5",
},
palette: {
mode: "dark",
primary: {
main: "#929aa5",
},
secondary: {
light: "#ff4081",
main: "#f50057",
dark: "#c51162",
contrastText: "#ffffff",
},
error: {
light: "#e57373",
main: "#f44336",
dark: "#d32f2f",
contrastText: "#ffffff",
},
warning: {
light: "#ffb74d",
main: "#ff9800",
dark: "#f57c00",
contrastText: "rgba(0, 0, 0, 0.87)",
},
info: {
light: "#64b5f6",
main: "#2196f3",
dark: "#1976d2",
contrastText: "#ffffff",
},
success: {
light: "#81c784",
main: "#4caf50",
dark: "#388e3c",
contrastText: "rgba(0, 0, 0, 0.87)",
},
grey: {
"50": "#fafafa",
"100": "#f5f5f5",
"200": "#eeeeee",
"300": "#e0e0e0",
"400": "#bdbdbd",
"500": "#9e9e9e",
"600": "#757575",
"700": "#616161",
"800": "#424242",
"900": "#212121",
A100: "#d5d5d5",
A200: "#aaaaaa",
A400: "#303030",
A700: "#616161",
},
contrastThreshold: 3,
tonalOffset: 0.2,
text: {
primary: "#929aa5",
secondary: "rgba(0, 0, 0, 0.54)",
disabled: "rgba(0, 0, 0, 0.38)",
},
divider: "rgba(0, 0, 0, 0.12)",
background: {
default: "#2f343e",
paper: "#2f343e",
default: "#2f343e",
},
action: {
active: "#929aa5",
hover: "#929aa5",
hoverOpacity: 0.04,
selected: "#929aa5",
selectedOpacity: 0.08,
disabled: "rgba(0, 0, 0, 0.26)",
disabledBackground: "rgba(0, 0, 0, 0.12)",
disabledOpacity: 0.38,
focus: "rgba(0, 0, 0, 0.12)",
focusOpacity: 0.12,
activatedOpacity: 0.12,
},
},
overrides: {
components: {
MuiCssBaseline: {
"@global": {
body: {
backgroundColor: "#2f343e",
color: "#929aa5",
styleOverrides: {
"@global": {
body: {
backgroundColor: "#2f343e",
color: "#929aa5",
},
},
},
},
MuiOutlinedInput: {
root: {
"& $notchedOutline": {
borderColor: "#929aa5",
},
"&:hover:not($disabled):not($focused):not($error) $notchedOutline": {
borderColor: "#929aa5",
borderWidth: 2,
},
"&$focused $notchedOutline": {
borderColor: "#929aa5",
styleOverrides: {
root: {
"& $notchedOutline": {
borderColor: "#929aa5",
},
"&:hover:not($disabled):not($focused):not($error) $notchedOutline": {
borderColor: "#929aa5",
borderWidth: 2,
},
"&$focused $notchedOutline": {
borderColor: "#929aa5",
},
},
notchedOutline: {},
},
notchedOutline: {},
},
MuiCheckbox: {
root: {
color: "#929aa5",
styleOverrides: {
root: {
color: "#929aa5",
},
},
},
MuiInputBase: {
input: {
color: "#929aa5",
styleOverrides: {
input: {
color: "#929aa5",
},
},
},
MuiInputLabel: {
root: {
color: "#929aa5",
styleOverrides: {
root: {
color: "#929aa5",
},
},
},
},

View File

@ -1,4 +1,4 @@
import { createTheme } from "@material-ui/core/styles";
import { createTheme } from "@mui/material/styles";
const Light = createTheme({
custom: {
@ -6,12 +6,80 @@ const Light = createTheme({
loadingBar: "#000",
},
palette: {
mode: "light",
primary: {
main: "#1976d2",
},
secondary: {
light: "#ff4081",
main: "#f50057",
dark: "#c51162",
contrastText: "#ffffff",
},
error: {
light: "#e57373",
main: "#f44336",
dark: "#d32f2f",
contrastText: "#ffffff",
},
warning: {
light: "#ffb74d",
main: "#ff9800",
dark: "#f57c00",
contrastText: "rgba(0, 0, 0, 0.87)",
},
info: {
light: "#64b5f6",
main: "#2196f3",
dark: "#1976d2",
contrastText: "#ffffff",
},
success: {
light: "#81c784",
main: "#4caf50",
dark: "#388e3c",
contrastText: "rgba(0, 0, 0, 0.87)",
},
grey: {
"50": "#fafafa",
"100": "#f5f5f5",
"200": "#eeeeee",
"300": "#e0e0e0",
"400": "#bdbdbd",
"500": "#9e9e9e",
"600": "#757575",
"700": "#616161",
"800": "#424242",
"900": "#212121",
A100: "#d5d5d5",
A200: "#aaaaaa",
A400: "#303030",
A700: "#616161",
},
contrastThreshold: 3,
tonalOffset: 0.2,
text: {
primary: "rgba(0, 0, 0, 0.87)",
secondary: "rgba(0, 0, 0, 0.54)",
disabled: "rgba(0, 0, 0, 0.38)",
},
divider: "rgba(0, 0, 0, 0.12)",
background: {
default: "#fff",
paper: "#fff",
default: "#fff",
},
action: {
active: "rgba(0, 0, 0, 0.54)",
hover: "rgba(0, 0, 0, 0.04)",
hoverOpacity: 0.04,
selected: "rgba(0, 0, 0, 0.08)",
selectedOpacity: 0.08,
disabled: "rgba(0, 0, 0, 0.26)",
disabledBackground: "rgba(0, 0, 0, 0.12)",
disabledOpacity: 0.38,
focus: "rgba(0, 0, 0, 0.12)",
focusOpacity: 0.12,
activatedOpacity: 0.12,
},
},
});

View File

@ -1,18 +1,28 @@
declare module "@material-ui/core/styles/createTheme" {
import React from "react";
import { Theme } from "@mui/material";
declare module "@mui/material/styles" {
interface Theme {
custom: {
icon: React.CSSProperties["color"];
loadingBar: React.CSSProperties["color"];
};
}
interface ThemeOptions {
custom: {
icon: React.CSSProperties["color"];
loadingBar: React.CSSProperties["color"];
custom?: {
icon?: React.CSSProperties["color"];
loadingBar?: React.CSSProperties["color"];
};
}
}
declare module "@mui/styles/defaultTheme" {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface DefaultTheme extends Theme {}
}
export { default as Light } from "@themes/Light";
export { default as Dark } from "@themes/Dark";
export { default as Grey } from "@themes/Grey";

View File

@ -2,10 +2,11 @@ import React, { useEffect, useCallback, useState } from "react";
import { IconDefinition, faCopy, faKey, faTimesCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { makeStyles, Typography, Button, IconButton, Link, CircularProgress, TextField } from "@material-ui/core";
import { red } from "@material-ui/core/colors";
import { Typography, Button, IconButton, Link, CircularProgress, TextField, Theme } from "@mui/material";
import { red } from "@mui/material/colors";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames";
import QRCode from "qrcode.react";
import { QRCodeSVG } from "qrcode.react";
import { useTranslation } from "react-i18next";
import { useLocation, useNavigate } from "react-router-dom";
@ -18,7 +19,7 @@ import { completeTOTPRegistrationProcess } from "@services/RegisterDevice";
import { extractIdentityToken } from "@utils/IdentityToken";
const RegisterOneTimePassword = function () {
const style = useStyles();
const styles = useStyles();
const navigate = useNavigate();
const location = useLocation();
// The secret retrieved from the API is all is ok.
@ -72,39 +73,40 @@ const RegisterOneTimePassword = function () {
function SecretButton(text: string | undefined, action: string, icon: IconDefinition) {
return (
<IconButton
className={style.secretButtons}
className={styles.secretButtons}
color="primary"
onClick={() => {
navigator.clipboard.writeText(`${text}`);
createSuccessNotification(`${action}`);
}}
size="large"
>
<FontAwesomeIcon icon={icon} />
</IconButton>
);
}
const qrcodeFuzzyStyle = isLoading || hasErrored ? style.fuzzy : undefined;
const qrcodeFuzzyStyle = isLoading || hasErrored ? styles.fuzzy : undefined;
return (
<LoginLayout title={translate("Scan QR Code")}>
<div className={style.root}>
<div className={style.googleAuthenticator}>
<Typography className={style.googleAuthenticatorText}>
<div className={styles.root}>
<div className={styles.googleAuthenticator}>
<Typography className={styles.googleAuthenticatorText}>
{translate("Need Google Authenticator?")}
</Typography>
<AppStoreBadges
iconSize={128}
targetBlank
className={style.googleAuthenticatorBadges}
className={styles.googleAuthenticatorBadges}
googlePlayLink={GoogleAuthenticator.googlePlay}
appleStoreLink={GoogleAuthenticator.appleStore}
/>
</div>
<div className={classnames(qrcodeFuzzyStyle, style.qrcodeContainer)}>
<Link href={secretURL}>
<QRCode value={secretURL} className={style.qrcode} size={256} />
{!hasErrored && isLoading ? <CircularProgress className={style.loader} size={128} /> : null}
{hasErrored ? <FontAwesomeIcon className={style.failureIcon} icon={faTimesCircle} /> : null}
<div className={classnames(qrcodeFuzzyStyle, styles.qrcodeContainer)}>
<Link href={secretURL} underline="hover">
<QRCodeSVG value={secretURL} className={styles.qrcode} size={256} />
{!hasErrored && isLoading ? <CircularProgress className={styles.loader} size={128} /> : null}
{hasErrored ? <FontAwesomeIcon className={styles.failureIcon} icon={faTimesCircle} /> : null}
</Link>
</div>
<div>
@ -112,7 +114,7 @@ const RegisterOneTimePassword = function () {
<TextField
id="secret-url"
label={translate("Secret")}
className={style.secret}
className={styles.secret}
value={secretURL}
InputProps={{
readOnly: true,
@ -129,7 +131,7 @@ const RegisterOneTimePassword = function () {
<Button
variant="contained"
color="primary"
className={style.doneButton}
className={styles.doneButton}
onClick={handleDoneClick}
disabled={isLoading}
>
@ -142,7 +144,7 @@ const RegisterOneTimePassword = function () {
export default RegisterOneTimePassword;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
root: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useState } from "react";
import { Button, makeStyles, Typography } from "@material-ui/core";
import { Button, Theme, Typography } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useLocation, useNavigate } from "react-router-dom";
import FingerTouchIcon from "@components/FingerTouchIcon";
@ -12,7 +13,7 @@ import { performAttestationCeremony } from "@services/Webauthn";
import { extractIdentityToken } from "@utils/IdentityToken";
const RegisterWebauthn = function () {
const style = useStyles();
const styles = useStyles();
const navigate = useNavigate();
const location = useLocation();
const { createErrorNotification } = useNotifications();
@ -84,10 +85,10 @@ const RegisterWebauthn = function () {
return (
<LoginLayout title="Touch Security Key">
<div className={style.icon}>
<div className={styles.icon}>
<FingerTouchIcon size={64} animated />
</div>
<Typography className={style.instruction}>Touch the token on your security key</Typography>
<Typography className={styles.instruction}>Touch the token on your security key</Typography>
<Button color="primary" onClick={handleBackClick}>
Retry
</Button>
@ -100,7 +101,7 @@ const RegisterWebauthn = function () {
export default RegisterWebauthn;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
icon: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React from "react";
import { Grid, Typography, useTheme } from "@material-ui/core";
import { Grid, Theme, Typography, useTheme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import ReactLoading from "react-loading";
export interface Props {
@ -9,9 +10,11 @@ export interface Props {
const BaseLoadingPage = function (props: Props) {
const theme = useTheme();
const styles = useStyles();
return (
<Grid container alignItems="center" justifyContent="center" style={{ minHeight: "100vh" }}>
<Grid item style={{ textAlign: "center", display: "inline-block" }}>
<Grid container className={styles.gridOuter}>
<Grid item className={styles.gridInner}>
<ReactLoading width={64} height={64} color={theme.custom.loadingBar} type="bars" />
<Typography>{props.message}...</Typography>
</Grid>
@ -20,3 +23,15 @@ const BaseLoadingPage = function (props: Props) {
};
export default BaseLoadingPage;
const useStyles = makeStyles((theme: Theme) => ({
gridOuter: {
alignItems: "center",
justifyContent: "center",
minHeight: "100vh",
},
gridInner: {
textAlign: "center",
display: "inline-block",
},
}));

View File

@ -1,16 +1,17 @@
import React from "react";
import { Typography, makeStyles } from "@material-ui/core";
import { Theme, Typography } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next";
import SuccessIcon from "@components/SuccessIcon";
const Authenticated = function () {
const classes = useStyles();
const styles = useStyles();
const { t: translate } = useTranslation();
return (
<div id="authenticated-stage">
<div className={classes.iconContainer}>
<div className={styles.iconContainer}>
<SuccessIcon />
</div>
<Typography>{translate("Authenticated")}</Typography>
@ -20,7 +21,7 @@ const Authenticated = function () {
export default Authenticated;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
iconContainer: {
marginBottom: theme.spacing(2),
flex: "0 0 100%",

View File

@ -1,6 +1,7 @@
import React from "react";
import { Grid, makeStyles, Button } from "@material-ui/core";
import { Grid, Button, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
@ -13,7 +14,7 @@ export interface Props {
}
const AuthenticatedView = function (props: Props) {
const style = useStyles();
const styles = useStyles();
const navigate = useNavigate();
const { t: translate } = useTranslation();
@ -29,7 +30,7 @@ const AuthenticatedView = function (props: Props) {
{translate("Logout")}
</Button>
</Grid>
<Grid item xs={12} className={style.mainContainer}>
<Grid item xs={12} className={styles.mainContainer}>
<Authenticated />
</Grid>
</Grid>
@ -39,7 +40,7 @@ const AuthenticatedView = function (props: Props) {
export default AuthenticatedView;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
mainContainer: {
border: "1px solid #d6d6d6",
borderRadius: "10px",

View File

@ -1,5 +1,6 @@
import React, { useEffect, Fragment, ReactNode, useState } from "react";
import { AccountBox, CheckBox, Contacts, Drafts, Group } from "@mui/icons-material";
import {
Button,
Grid,
@ -9,11 +10,11 @@ import {
ListItemText,
Tooltip,
Typography,
makeStyles,
Checkbox,
FormControlLabel,
} from "@material-ui/core";
import { AccountBox, CheckBox, Contacts, Drafts, Group } from "@material-ui/icons";
Theme,
} from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
@ -44,7 +45,7 @@ function scopeNameToAvatar(id: string) {
}
const ConsentView = function (props: Props) {
const classes = useStyles();
const styles = useStyles();
const navigate = useNavigate();
const redirect = useRedirector();
const { createErrorNotification, resetNotification } = useNotifications();
@ -137,7 +138,7 @@ const ConsentView = function (props: Props) {
"Client ID: " + resp?.client_id
}
>
<Typography className={classes.clientDescription}>
<Typography className={styles.clientDescription}>
{resp !== undefined && resp.client_description !== ""
? resp.client_description
: resp?.client_id}
@ -149,8 +150,8 @@ const ConsentView = function (props: Props) {
<div>{translate("The above application is requesting the following permissions")}:</div>
</Grid>
<Grid item xs={12}>
<div className={classes.scopesListContainer}>
<List className={classes.scopesList}>
<div className={styles.scopesListContainer}>
<List className={styles.scopesList}>
{resp?.scopes.map((scope: string) => (
<Tooltip title={"Scope " + scope}>
<ListItem id={"scope-" + scope} dense>
@ -180,7 +181,7 @@ const ConsentView = function (props: Props) {
color="primary"
/>
}
className={classes.preConfigure}
className={styles.preConfigure}
label={translate("Remember Consent")}
/>
</Tooltip>
@ -191,7 +192,7 @@ const ConsentView = function (props: Props) {
<Grid item xs={6}>
<Button
id="accept-button"
className={classes.button}
className={styles.button}
disabled={!resp}
onClick={handleAcceptConsent}
color="primary"
@ -203,7 +204,7 @@ const ConsentView = function (props: Props) {
<Grid item xs={6}>
<Button
id="deny-button"
className={classes.button}
className={styles.button}
disabled={!resp}
onClick={handleRejectConsent}
color="secondary"
@ -220,7 +221,7 @@ const ConsentView = function (props: Props) {
);
};
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
container: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
import { makeStyles, Grid, Button, FormControlLabel, Checkbox, Link } from "@material-ui/core";
import { Grid, Button, FormControlLabel, Checkbox, Link, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
@ -29,7 +30,7 @@ export interface Props {
}
const FirstFactorForm = function (props: Props) {
const style = useStyles();
const styles = useStyles();
const navigate = useNavigate();
const redirectionURL = useRedirectionURL();
const requestMethod = useRequestMethod();
@ -170,7 +171,7 @@ const FirstFactorForm = function (props: Props) {
/>
</Grid>
{props.rememberMe ? (
<Grid item xs={12} className={classnames(style.actionRow)}>
<Grid item xs={12} className={classnames(styles.actionRow)}>
<FormControlLabel
control={
<Checkbox
@ -192,7 +193,7 @@ const FirstFactorForm = function (props: Props) {
color="primary"
/>
}
className={style.rememberMe}
className={styles.rememberMe}
label={translate("Remember me")}
/>
</Grid>
@ -210,12 +211,13 @@ const FirstFactorForm = function (props: Props) {
</Button>
</Grid>
{props.resetPassword ? (
<Grid item xs={12} className={classnames(style.actionRow, style.flexEnd)}>
<Grid item xs={12} className={classnames(styles.actionRow, styles.flexEnd)}>
<Link
id="reset-password-button"
component="button"
onClick={handleResetPasswordClick}
className={style.resetLink}
className={styles.resetLink}
underline="hover"
>
{translate("Reset password?")}
</Link>
@ -228,7 +230,7 @@ const FirstFactorForm = function (props: Props) {
export default FirstFactorForm;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
actionRow: {
display: "flex",
flexDirection: "row",

View File

@ -1,6 +1,7 @@
import React, { ReactNode, useState } from "react";
import { makeStyles, Typography, Grid, Button, Container } from "@material-ui/core";
import { Typography, Grid, Button, Container, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import PushNotificationIcon from "@components/PushNotificationIcon";
@ -102,7 +103,7 @@ interface DeviceItemProps {
function DeviceItem(props: DeviceItemProps) {
const className = "device-option-" + props.id;
const idName = "device-" + props.device.id;
const style = makeStyles((theme) => ({
const style = makeStyles((theme: Theme) => ({
item: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),
@ -147,7 +148,7 @@ interface MethodItemProps {
function MethodItem(props: MethodItemProps) {
const className = "method-option-" + props.id;
const idName = "method-" + props.method;
const style = makeStyles((theme) => ({
const style = makeStyles((theme: Theme) => ({
item: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React, { ReactNode } from "react";
import { makeStyles } from "@material-ui/core";
import { Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames";
interface IconWithContextProps {
@ -12,7 +13,7 @@ interface IconWithContextProps {
const IconWithContext = function (props: IconWithContextProps) {
const iconSize = 64;
const style = makeStyles((theme) => ({
const styles = makeStyles((theme: Theme) => ({
root: {},
iconContainer: {
display: "flex",
@ -29,11 +30,11 @@ const IconWithContext = function (props: IconWithContextProps) {
}))();
return (
<div className={classnames(props.className, style.root)}>
<div className={style.iconContainer}>
<div className={style.icon}>{props.icon}</div>
<div className={classnames(props.className, styles.root)}>
<div className={styles.iconContainer}>
<div className={styles.icon}>{props.icon}</div>
</div>
<div className={style.context}>{props.children}</div>
<div className={styles.context}>{props.children}</div>
</div>
);
};

View File

@ -1,6 +1,7 @@
import React, { ReactNode, Fragment } from "react";
import { makeStyles, Typography, Link, useTheme } from "@material-ui/core";
import { Typography, Link, Theme, Box } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames";
import { useTranslation } from "react-i18next";
@ -27,7 +28,7 @@ export interface Props {
}
const DefaultMethodContainer = function (props: Props) {
const style = useStyles();
const styles = useStyles();
const { t: translate } = useTranslation();
const registerMessage = props.registered
? props.title === "Push Notification"
@ -56,17 +57,17 @@ const DefaultMethodContainer = function (props: Props) {
return (
<div id={props.id}>
<Typography variant="h6">{props.title}</Typography>
<div className={classnames(style.container, stateClass)} id="2fa-container">
<div className={style.containerFlex}>{container}</div>
<div className={classnames(styles.container, stateClass)} id="2fa-container">
<div className={styles.containerFlex}>{container}</div>
</div>
{props.onSelectClick && props.registered ? (
<Link component="button" id="selection-link" onClick={props.onSelectClick}>
<Link component="button" id="selection-link" onClick={props.onSelectClick} underline="hover">
{selectMessage}
</Link>
) : null}
{(props.onRegisterClick && props.title !== "Push Notification") ||
(props.onRegisterClick && props.title === "Push Notification" && props.duoSelfEnrollment) ? (
<Link component="button" id="register-link" onClick={props.onRegisterClick}>
<Link component="button" id="register-link" onClick={props.onRegisterClick} underline="hover">
{registerMessage}
</Link>
) : null}
@ -76,7 +77,7 @@ const DefaultMethodContainer = function (props: Props) {
export default DefaultMethodContainer;
const useStyles = makeStyles(() => ({
const useStyles = makeStyles((theme: Theme) => ({
container: {
height: "200px",
},
@ -89,6 +90,16 @@ const useStyles = makeStyles(() => ({
alignContent: "center",
justifyContent: "center",
},
containerMethod: {
marginBottom: theme.spacing(2),
},
info: {
marginBottom: theme.spacing(2),
flex: "0 0 100%",
},
infoTypography: {
color: "#5858ff",
},
}));
interface NotRegisteredContainerProps {
@ -98,16 +109,17 @@ interface NotRegisteredContainerProps {
function NotRegisteredContainer(props: NotRegisteredContainerProps) {
const { t: translate } = useTranslation();
const theme = useTheme();
const styles = useStyles();
return (
<Fragment>
<div style={{ marginBottom: theme.spacing(2), flex: "0 0 100%" }}>
<Box className={styles.info}>
<InformationIcon />
</div>
<Typography style={{ color: "#5858ff" }}>
</Box>
<Typography className={styles.infoTypography}>
{translate("The resource you're attempting to access requires two-factor authentication")}
</Typography>
<Typography style={{ color: "#5858ff" }}>
<Typography className={styles.infoTypography}>
{props.title === "Push Notification"
? props.duoSelfEnrollment
? translate("Register your first device by clicking on the link below")
@ -124,10 +136,11 @@ interface MethodContainerProps {
}
function MethodContainer(props: MethodContainerProps) {
const theme = useTheme();
const styles = useStyles();
return (
<Fragment>
<div style={{ marginBottom: theme.spacing(2) }}>{props.children}</div>
<Box className={styles.containerMethod}>{props.children}</Box>
<Typography>{props.explanation}</Typography>
</Fragment>
);

View File

@ -1,15 +1,7 @@
import React, { ReactNode } from "react";
import {
Dialog,
Grid,
makeStyles,
DialogContent,
Button,
DialogActions,
Typography,
useTheme,
} from "@material-ui/core";
import { Dialog, Grid, DialogContent, Button, DialogActions, Typography, useTheme, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next";
import FingerTouchIcon from "@components/FingerTouchIcon";
@ -27,7 +19,7 @@ export interface Props {
}
const MethodSelectionDialog = function (props: Props) {
const style = useStyles();
const styles = useStyles();
const theme = useTheme();
const { t: translate } = useTranslation();
@ -36,7 +28,7 @@ const MethodSelectionDialog = function (props: Props) {
);
return (
<Dialog open={props.open} className={style.root} onClose={props.onClose}>
<Dialog open={props.open} className={styles.root} onClose={props.onClose}>
<DialogContent>
<Grid container justifyContent="center" spacing={1} id="methods-dialog">
{props.methods.has(SecondFactorMethod.TOTP) ? (
@ -76,7 +68,7 @@ const MethodSelectionDialog = function (props: Props) {
export default MethodSelectionDialog;
const useStyles = makeStyles(() => ({
const useStyles = makeStyles((theme: Theme) => ({
root: {
textAlign: "center",
},
@ -91,7 +83,7 @@ interface MethodItemProps {
}
function MethodItem(props: MethodItemProps) {
const style = makeStyles((theme) => ({
const style = makeStyles((theme: Theme) => ({
item: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),

View File

@ -1,6 +1,7 @@
import React, { Fragment } from "react";
import { makeStyles } from "@material-ui/core";
import { Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames";
import OtpInput from "react-otp-input";
@ -20,11 +21,11 @@ export interface Props {
}
const OTPDial = function (props: Props) {
const style = useStyles();
const styles = useStyles();
return (
<IconWithContext icon={<Icon state={props.state} period={props.period} />}>
<span className={style.otpInput} id="otp-input">
<span className={styles.otpInput} id="otp-input">
<OtpInput
shouldAutoFocus
onChange={props.onChange}
@ -33,7 +34,10 @@ const OTPDial = function (props: Props) {
isDisabled={props.state === State.InProgress || props.state === State.Success}
isInputNum
hasErrored={props.state === State.Failure}
inputStyle={classnames(style.otpDigitInput, props.state === State.Failure ? style.inputError : "")}
inputStyle={classnames(
styles.otpDigitInput,
props.state === State.Failure ? styles.inputError : "",
)}
/>
</span>
</IconWithContext>
@ -42,7 +46,7 @@ const OTPDial = function (props: Props) {
export default OTPDial;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
timeProgress: {},
register: {
marginTop: theme.spacing(),

View File

@ -1,6 +1,7 @@
import React, { useEffect, useCallback, useRef, useState, ReactNode } from "react";
import { Button, makeStyles } from "@material-ui/core";
import { Button, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import FailureIcon from "@components/FailureIcon";
import PushNotificationIcon from "@components/PushNotificationIcon";
@ -40,7 +41,7 @@ export interface Props {
}
const PushNotificationMethod = function (props: Props) {
const style = useStyles();
const styles = useStyles();
const [state, setState] = useState(State.SignInInProgress);
const redirectionURL = useRedirectionURL();
const mounted = useIsMountedRef();
@ -216,7 +217,7 @@ const PushNotificationMethod = function (props: Props) {
onSelectClick={fetchDuoDevicesFunc}
onRegisterClick={() => window.open(enroll_url, "_blank")}
>
<div className={style.icon}>{icon}</div>
<div className={styles.icon}>{icon}</div>
<div className={state !== State.Failure ? "hidden" : ""}>
<Button color="secondary" onClick={signInFunc}>
Retry
@ -228,7 +229,7 @@ const PushNotificationMethod = function (props: Props) {
export default PushNotificationMethod;
const useStyles = makeStyles(() => ({
const useStyles = makeStyles((theme: Theme) => ({
icon: {
width: "64px",
height: "64px",

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react";
import { Grid, makeStyles, Button } from "@material-ui/core";
import { Grid, Button, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next";
import { Route, Routes, useNavigate } from "react-router-dom";
@ -35,7 +36,7 @@ export interface Props {
}
const SecondFactorForm = function (props: Props) {
const style = useStyles();
const styles = useStyles();
const navigate = useNavigate();
const [methodSelectionOpen, setMethodSelectionOpen] = useState(false);
const { createInfoNotification, createErrorNotification } = useNotifications();
@ -106,7 +107,7 @@ const SecondFactorForm = function (props: Props) {
</Button>
) : null}
</Grid>
<Grid item xs={12} className={style.methodContainer}>
<Grid item xs={12} className={styles.methodContainer}>
<Routes>
<Route
path={SecondFactorTOTPSubRoute}
@ -159,7 +160,7 @@ const SecondFactorForm = function (props: Props) {
export default SecondFactorForm;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
methodContainer: {
border: "1px solid #d6d6d6",
borderRadius: "10px",

View File

@ -1,7 +1,7 @@
import React, { Fragment, useCallback, useEffect, useRef, useState } from "react";
import { Button, makeStyles, useTheme } from "@material-ui/core";
import { CSSProperties } from "@material-ui/styles";
import { Button, Theme, useTheme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import FailureIcon from "@components/FailureIcon";
import FingerTouchIcon from "@components/FingerTouchIcon";
@ -38,7 +38,7 @@ export interface Props {
const WebauthnMethod = function (props: Props) {
const signInTimeout = 30;
const [state, setState] = useState(State.WaitTouch);
const style = useStyles();
const styles = useStyles();
const redirectionURL = useRedirectionURL();
const mounted = useIsMountedRef();
const [timerPercent, triggerTimer] = useTimer(signInTimeout * 1000 - 500);
@ -162,7 +162,7 @@ const WebauthnMethod = function (props: Props) {
state={methodState}
onRegisterClick={props.onRegisterClick}
>
<div className={style.icon}>
<div className={styles.icon}>
<Icon state={state} timer={timerPercent} onRetryClick={doInitiateSignIn} />
</div>
</MethodContainer>
@ -171,7 +171,7 @@ const WebauthnMethod = function (props: Props) {
export default WebauthnMethod;
const useStyles = makeStyles(() => ({
const useStyles = makeStyles((theme: Theme) => ({
icon: {
display: "inline-block",
},
@ -188,16 +188,18 @@ function Icon(props: IconProps) {
const state = props.state as State;
const theme = useTheme();
const progressBarStyle: CSSProperties = {
marginTop: theme.spacing(),
};
const styles = makeStyles((theme: Theme) => ({
progressBar: {
marginTop: theme.spacing(),
},
}))();
const touch = (
<IconWithContext
icon={<FingerTouchIcon size={64} animated strong />}
className={state === State.WaitTouch ? undefined : "hidden"}
>
<LinearProgressBar value={props.timer} style={progressBarStyle} height={theme.spacing(2)} />
<LinearProgressBar value={props.timer} className={styles.progressBar} height={theme.spacing(2)} />
</IconWithContext>
);

View File

@ -1,6 +1,7 @@
import React, { useEffect, useCallback, useState } from "react";
import { Typography, makeStyles } from "@material-ui/core";
import { Theme, Typography } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next";
import { Navigate } from "react-router-dom";
@ -16,7 +17,7 @@ export interface Props {}
const SignOut = function (props: Props) {
const mounted = useIsMountedRef();
const style = useStyles();
const styles = useStyles();
const { createErrorNotification } = useNotifications();
const redirectionURL = useRedirectionURL();
const redirector = useRedirector();
@ -56,14 +57,14 @@ const SignOut = function (props: Props) {
return (
<LoginLayout title={translate("Sign out")}>
<Typography className={style.typo}>{translate("You're being signed out and redirected")}...</Typography>
<Typography className={styles.typo}>{translate("You're being signed out and redirected")}...</Typography>
</LoginLayout>
);
};
export default SignOut;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
typo: {
padding: theme.spacing(),
},

View File

@ -1,6 +1,7 @@
import React, { useState } from "react";
import { Grid, Button, makeStyles } from "@material-ui/core";
import { Grid, Button, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
@ -11,7 +12,7 @@ import LoginLayout from "@layouts/LoginLayout";
import { initiateResetPasswordProcess } from "@services/ResetPassword";
const ResetPasswordStep1 = function () {
const style = useStyles();
const styles = useStyles();
const [username, setUsername] = useState("");
const [error, setError] = useState(false);
const { createInfoNotification, createErrorNotification } = useNotifications();
@ -42,7 +43,7 @@ const ResetPasswordStep1 = function () {
return (
<LoginLayout title={translate("Reset password")} id="reset-password-step1-stage">
<Grid container className={style.root} spacing={2}>
<Grid container className={styles.root} spacing={2}>
<Grid item xs={12}>
<FixedTextField
id="username-textfield"
@ -83,7 +84,7 @@ const ResetPasswordStep1 = function () {
export default ResetPasswordStep1;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
root: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),

View File

@ -1,7 +1,8 @@
import React, { useCallback, useEffect, useState } from "react";
import { Button, Grid, IconButton, InputAdornment, makeStyles } from "@material-ui/core";
import { Visibility, VisibilityOff } from "@material-ui/icons";
import { Visibility, VisibilityOff } from "@mui/icons-material";
import { Button, Grid, IconButton, InputAdornment, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames";
import { useTranslation } from "react-i18next";
import { useLocation, useNavigate } from "react-router-dom";
@ -17,7 +18,7 @@ import { completeResetPasswordProcess, resetPassword } from "@services/ResetPass
import { extractIdentityToken } from "@utils/IdentityToken";
const ResetPasswordStep2 = function () {
const style = useStyles();
const styles = useStyles();
const location = useLocation();
const [formDisabled, setFormDisabled] = useState(true);
const [password1, setPassword1] = useState("");
@ -110,7 +111,7 @@ const ResetPasswordStep2 = function () {
return (
<LoginLayout title={translate("Enter new password")} id="reset-password-step2-stage">
<Grid container className={style.root} spacing={2}>
<Grid container className={styles.root} spacing={2}>
<Grid item xs={12}>
<FixedTextField
id="password1-textfield"
@ -121,7 +122,7 @@ const ResetPasswordStep2 = function () {
disabled={formDisabled}
onChange={(e) => setPassword1(e.target.value)}
error={errorPassword1}
className={classnames(style.fullWidth)}
className={classnames(styles.fullWidth)}
autoComplete="new-password"
InputProps={{
endAdornment: (
@ -130,6 +131,7 @@ const ResetPasswordStep2 = function () {
aria-label="toggle password visibility"
onClick={(e) => setShowPassword(!showPassword)}
edge="end"
size="large"
>
{showPassword ? <VisibilityOff></VisibilityOff> : <Visibility></Visibility>}
</IconButton>
@ -157,7 +159,7 @@ const ResetPasswordStep2 = function () {
ev.preventDefault();
}
}}
className={classnames(style.fullWidth)}
className={classnames(styles.fullWidth)}
autoComplete="new-password"
/>
</Grid>
@ -169,7 +171,7 @@ const ResetPasswordStep2 = function () {
name="password1"
disabled={formDisabled}
onClick={handleResetClick}
className={style.fullWidth}
className={styles.fullWidth}
>
{translate("Reset")}
</Button>
@ -181,7 +183,7 @@ const ResetPasswordStep2 = function () {
color="primary"
name="password2"
onClick={handleCancelClick}
className={style.fullWidth}
className={styles.fullWidth}
>
{translate("Cancel")}
</Button>
@ -193,7 +195,7 @@ const ResetPasswordStep2 = function () {
export default ResetPasswordStep2;
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
root: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),