mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
build(deps): update mui monorepo to v5.8.4 (major) (#3215)
This commit is contained in:
parent
0a9dd4727d
commit
841e495dca
|
@ -17,13 +17,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/cache": "11.9.3",
|
||||||
|
"@emotion/react": "11.9.3",
|
||||||
|
"@emotion/styled": "11.9.3",
|
||||||
"@fortawesome/fontawesome-svg-core": "6.1.1",
|
"@fortawesome/fontawesome-svg-core": "6.1.1",
|
||||||
"@fortawesome/free-regular-svg-icons": "6.1.1",
|
"@fortawesome/free-regular-svg-icons": "6.1.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.1.1",
|
"@fortawesome/free-solid-svg-icons": "6.1.1",
|
||||||
"@fortawesome/react-fontawesome": "0.1.18",
|
"@fortawesome/react-fontawesome": "0.1.18",
|
||||||
"@material-ui/core": "4.12.4",
|
"@mui/icons-material": "5.8.4",
|
||||||
"@material-ui/icons": "4.11.3",
|
"@mui/material": "5.8.4",
|
||||||
"@material-ui/styles": "4.11.5",
|
"@mui/styles": "5.8.4",
|
||||||
"axios": "0.27.2",
|
"axios": "0.27.2",
|
||||||
"classnames": "2.3.1",
|
"classnames": "2.3.1",
|
||||||
"i18next": "21.8.10",
|
"i18next": "21.8.10",
|
||||||
|
@ -151,7 +154,7 @@
|
||||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||||
"@typescript-eslint/parser": "5.29.0",
|
"@typescript-eslint/parser": "5.29.0",
|
||||||
"@vitejs/plugin-react": "1.3.2",
|
"@vitejs/plugin-react": "1.3.2",
|
||||||
"esbuild": "0.14.46",
|
"esbuild": "0.14.17",
|
||||||
"esbuild-jest": "0.5.0",
|
"esbuild-jest": "0.5.0",
|
||||||
"eslint": "8.18.0",
|
"eslint": "8.18.0",
|
||||||
"eslint-config-prettier": "8.5.0",
|
"eslint-config-prettier": "8.5.0",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,9 @@
|
||||||
import React, { useState, useEffect, Suspense } from "react";
|
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 { 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 { BrowserRouter as Router, Route, Routes } from "react-router-dom";
|
||||||
|
|
||||||
import NotificationBar from "@components/NotificationBar";
|
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 [notification, setNotification] = useState(null as Notification | null);
|
||||||
const [theme, setTheme] = useState(Theme());
|
const [theme, setTheme] = useState(Theme());
|
||||||
|
|
||||||
|
const cache = createCache({
|
||||||
|
key: "authelia",
|
||||||
|
nonce: props.nonce,
|
||||||
|
prepend: true,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (getTheme() === "auto") {
|
if (getTheme() === "auto") {
|
||||||
const query = window.matchMedia("(prefers-color-scheme: dark)");
|
const query = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
@ -66,35 +79,37 @@ const App: React.FC = () => {
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<CacheProvider value={cache}>
|
||||||
<Suspense fallback={<BaseLoadingPage message={"Loading"} />}>
|
<ThemeProvider theme={theme}>
|
||||||
<CssBaseline />
|
<Suspense fallback={<BaseLoadingPage message={"Loading"} />}>
|
||||||
<NotificationsContext.Provider value={{ notification, setNotification }}>
|
<CssBaseline />
|
||||||
<Router basename={getBasePath()}>
|
<NotificationsContext.Provider value={{ notification, setNotification }}>
|
||||||
<NotificationBar onClose={() => setNotification(null)} />
|
<Router basename={getBasePath()}>
|
||||||
<Routes>
|
<NotificationBar onClose={() => setNotification(null)} />
|
||||||
<Route path={ResetPasswordStep1Route} element={<ResetPasswordStep1 />} />
|
<Routes>
|
||||||
<Route path={ResetPasswordStep2Route} element={<ResetPasswordStep2 />} />
|
<Route path={ResetPasswordStep1Route} element={<ResetPasswordStep1 />} />
|
||||||
<Route path={RegisterWebauthnRoute} element={<RegisterWebauthn />} />
|
<Route path={ResetPasswordStep2Route} element={<ResetPasswordStep2 />} />
|
||||||
<Route path={RegisterOneTimePasswordRoute} element={<RegisterOneTimePassword />} />
|
<Route path={RegisterWebauthnRoute} element={<RegisterWebauthn />} />
|
||||||
<Route path={LogoutRoute} element={<SignOut />} />
|
<Route path={RegisterOneTimePasswordRoute} element={<RegisterOneTimePassword />} />
|
||||||
<Route path={ConsentRoute} element={<ConsentView />} />
|
<Route path={LogoutRoute} element={<SignOut />} />
|
||||||
<Route
|
<Route path={ConsentRoute} element={<ConsentView />} />
|
||||||
path={`${IndexRoute}*`}
|
<Route
|
||||||
element={
|
path={`${IndexRoute}*`}
|
||||||
<LoginPortal
|
element={
|
||||||
duoSelfEnrollment={getDuoSelfEnrollment()}
|
<LoginPortal
|
||||||
rememberMe={getRememberMe()}
|
duoSelfEnrollment={getDuoSelfEnrollment()}
|
||||||
resetPassword={getResetPassword()}
|
rememberMe={getRememberMe()}
|
||||||
resetPasswordCustomURL={getResetPasswordCustomURL()}
|
resetPassword={getResetPassword()}
|
||||||
/>
|
resetPasswordCustomURL={getResetPasswordCustomURL()}
|
||||||
}
|
/>
|
||||||
/>
|
}
|
||||||
</Routes>
|
/>
|
||||||
</Router>
|
</Routes>
|
||||||
</NotificationsContext.Provider>
|
</Router>
|
||||||
</Suspense>
|
</NotificationsContext.Provider>
|
||||||
</ThemeProvider>
|
</Suspense>
|
||||||
|
</ThemeProvider>
|
||||||
|
</CacheProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from "react";
|
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 AppleStore from "@assets/images/applestore-badge.svg";
|
||||||
import GooglePlay from "@assets/images/googleplay-badge.svg";
|
import GooglePlay from "@assets/images/googleplay-badge.svg";
|
||||||
|
@ -17,17 +18,21 @@ export interface Props {
|
||||||
const AppStoreBadges = function (props: Props) {
|
const AppStoreBadges = function (props: Props) {
|
||||||
const target = props.targetBlank ? "_blank" : undefined;
|
const target = props.targetBlank ? "_blank" : undefined;
|
||||||
|
|
||||||
const width = props.iconSize;
|
const styles = makeStyles((theme: Theme) => ({
|
||||||
|
badge: {
|
||||||
|
width: props.iconSize,
|
||||||
|
},
|
||||||
|
}))();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={props.className}>
|
<Box className={props.className}>
|
||||||
<Link href={props.googlePlayLink} target={target}>
|
<Link href={props.googlePlayLink} target={target} underline="hover">
|
||||||
<img src={GooglePlay} alt="google play" style={{ width }} />
|
<img src={GooglePlay} alt="google play" className={styles.badge} />
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={props.appleStoreLink} target={target}>
|
<Link href={props.appleStoreLink} target={target} underline="hover">
|
||||||
<img src={AppleStore} alt="apple store" style={{ width }} />
|
<img src={AppleStore} alt="apple store" className={styles.badge} />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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");
|
|
||||||
});
|
|
|
@ -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",
|
|
||||||
},
|
|
||||||
}));
|
|
|
@ -1,9 +1,15 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
import { createTheme } from "@mui/material/styles";
|
||||||
|
import { ThemeProvider } from "@mui/styles";
|
||||||
import { render } from "@testing-library/react";
|
import { render } from "@testing-library/react";
|
||||||
|
|
||||||
import FixedTextField from "@components/FixedTextField";
|
import FixedTextField from "@components/FixedTextField";
|
||||||
|
|
||||||
it("renders without crashing", () => {
|
it("renders without crashing", () => {
|
||||||
render(<FixedTextField />);
|
render(
|
||||||
|
<ThemeProvider theme={createTheme()}>
|
||||||
|
<FixedTextField />
|
||||||
|
</ThemeProvider>,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { makeStyles } from "@material-ui/core";
|
import { Theme } from "@mui/material/styles";
|
||||||
import TextField, { TextFieldProps } from "@material-ui/core/TextField";
|
import TextField, { TextFieldProps } from "@mui/material/TextField";
|
||||||
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component fixes outlined TextField
|
* This component fixes outlined TextField
|
||||||
|
@ -10,16 +11,16 @@ import TextField, { TextFieldProps } from "@material-ui/core/TextField";
|
||||||
* @param props the TextField props
|
* @param props the TextField props
|
||||||
*/
|
*/
|
||||||
const FixedTextField = function (props: TextFieldProps) {
|
const FixedTextField = function (props: TextFieldProps) {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
{...props}
|
{...props}
|
||||||
InputLabelProps={{
|
InputLabelProps={{
|
||||||
classes: {
|
classes: {
|
||||||
root: style.label,
|
root: styles.label,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
inputProps={{ autoCapitalize: props.autoCapitalize }}
|
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</TextField>
|
</TextField>
|
||||||
|
@ -28,7 +29,7 @@ const FixedTextField = function (props: TextFieldProps) {
|
||||||
|
|
||||||
export default FixedTextField;
|
export default FixedTextField;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
label: {
|
label: {
|
||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
paddingLeft: theme.spacing(0.1),
|
paddingLeft: theme.spacing(0.1),
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
import { createTheme } from "@mui/material/styles";
|
||||||
|
import { ThemeProvider } from "@mui/styles";
|
||||||
import { render } from "@testing-library/react";
|
import { render } from "@testing-library/react";
|
||||||
|
|
||||||
import LinearProgressBar from "@components/LinearProgressBar";
|
import LinearProgressBar from "@components/LinearProgressBar";
|
||||||
|
|
||||||
it("renders without crashing", () => {
|
it("renders without crashing", () => {
|
||||||
render(<LinearProgressBar value={40} />);
|
render(
|
||||||
|
<ThemeProvider theme={createTheme()}>
|
||||||
|
<LinearProgressBar value={40} />)
|
||||||
|
</ThemeProvider>,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders adjusted height without crashing", () => {
|
it("renders adjusted height without crashing", () => {
|
||||||
render(<LinearProgressBar value={40} height={2} />);
|
render(
|
||||||
|
<ThemeProvider theme={createTheme()}>
|
||||||
|
<LinearProgressBar value={40} height={2} />
|
||||||
|
</ThemeProvider>,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { makeStyles, LinearProgress } from "@material-ui/core";
|
import { LinearProgress, Theme } from "@mui/material";
|
||||||
import { CSSProperties } from "@material-ui/styles";
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
value: number;
|
value: number;
|
||||||
height?: number;
|
height?: string | number;
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: CSSProperties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const LinearProgressBar = function (props: Props) {
|
const LinearProgressBar = function (props: Props) {
|
||||||
const style = makeStyles((theme) => ({
|
const styles = makeStyles((theme: Theme) => ({
|
||||||
progressRoot: {
|
progressRoot: {
|
||||||
height: props.height ? props.height : theme.spacing(),
|
height: props.height ? props.height : theme.spacing(),
|
||||||
},
|
},
|
||||||
|
@ -19,13 +18,13 @@ const LinearProgressBar = function (props: Props) {
|
||||||
transition: "transform .2s linear",
|
transition: "transform .2s linear",
|
||||||
},
|
},
|
||||||
}))();
|
}))();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
style={props.style as React.CSSProperties}
|
|
||||||
variant="determinate"
|
variant="determinate"
|
||||||
classes={{
|
classes={{
|
||||||
root: style.progressRoot,
|
root: styles.progressRoot,
|
||||||
bar1Determinate: style.transition,
|
bar1Determinate: styles.transition,
|
||||||
}}
|
}}
|
||||||
value={props.value}
|
value={props.value}
|
||||||
className={props.className}
|
className={props.className}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import React, { useState, useEffect } from "react";
|
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 { useNotifications } from "@hooks/NotificationsContext";
|
||||||
import { Notification } from "@models/Notifications";
|
import { Notification } from "@models/Notifications";
|
||||||
|
|
||||||
|
@ -10,12 +9,18 @@ export interface Props {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NotificationBarTransitionProps = Omit<SlideProps, "direction">;
|
||||||
|
|
||||||
|
function NotificationBarTransition(props: NotificationBarTransitionProps) {
|
||||||
|
return <Slide {...props} direction={"left"} />;
|
||||||
|
}
|
||||||
|
|
||||||
const NotificationBar = function (props: Props) {
|
const NotificationBar = function (props: Props) {
|
||||||
const [tmpNotification, setTmpNotification] = useState(null as Notification | null);
|
const [tmpNotification, setTmpNotification] = useState(null as Notification | null);
|
||||||
const { notification } = useNotifications();
|
const { notification } = useNotifications();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (notification && notification !== null) {
|
if (notification) {
|
||||||
setTmpNotification(notification);
|
setTmpNotification(notification);
|
||||||
}
|
}
|
||||||
}, [notification, setTmpNotification]);
|
}, [notification, setTmpNotification]);
|
||||||
|
@ -28,15 +33,18 @@ const NotificationBar = function (props: Props) {
|
||||||
anchorOrigin={{ vertical: "top", horizontal: "right" }}
|
anchorOrigin={{ vertical: "top", horizontal: "right" }}
|
||||||
autoHideDuration={tmpNotification ? tmpNotification.timeout * 1000 : 10000}
|
autoHideDuration={tmpNotification ? tmpNotification.timeout * 1000 : 10000}
|
||||||
onClose={props.onClose}
|
onClose={props.onClose}
|
||||||
|
TransitionComponent={NotificationBarTransition}
|
||||||
TransitionProps={{
|
TransitionProps={{
|
||||||
onExited: () => setTmpNotification(null),
|
onExited: () => setTmpNotification(null),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ColoredSnackbarContent
|
{tmpNotification ? (
|
||||||
className="notification"
|
<Alert severity={tmpNotification.level} variant={"filled"} elevation={6} className={"notification"}>
|
||||||
level={tmpNotification ? tmpNotification.level : "info"}
|
{tmpNotification.message}
|
||||||
message={tmpNotification ? tmpNotification.message : ""}
|
</Alert>
|
||||||
/>
|
) : (
|
||||||
|
<Alert severity={"success"} elevation={6} variant={"filled"} className={"notification"} />
|
||||||
|
)}
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useEffect, useState } from "react";
|
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 classnames from "classnames";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import zxcvbn from "zxcvbn";
|
import zxcvbn from "zxcvbn";
|
||||||
|
@ -13,20 +14,12 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const PasswordMeter = function (props: Props) {
|
const PasswordMeter = function (props: Props) {
|
||||||
|
const { t: translate } = useTranslation();
|
||||||
|
|
||||||
const [progressColor] = useState(["#D32F2F", "#FF5722", "#FFEB3B", "#AFB42B", "#62D32F"]);
|
const [progressColor] = useState(["#D32F2F", "#FF5722", "#FFEB3B", "#AFB42B", "#62D32F"]);
|
||||||
const [passwordScore, setPasswordScore] = useState(0);
|
const [passwordScore, setPasswordScore] = useState(0);
|
||||||
const [maxScores, setMaxScores] = useState(0);
|
const [maxScores, setMaxScores] = useState(0);
|
||||||
const [feedback, setFeedback] = useState("");
|
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(() => {
|
useEffect(() => {
|
||||||
const password = props.value;
|
const password = props.value;
|
||||||
|
@ -106,17 +99,23 @@ const PasswordMeter = function (props: Props) {
|
||||||
}
|
}
|
||||||
}, [props, translate]);
|
}, [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 (
|
return (
|
||||||
<div style={{ width: "100%" }}>
|
<Box className={styles.progressContainer}>
|
||||||
<div
|
<Box title={feedback} className={classnames(styles.progressBar)} />
|
||||||
title={feedback}
|
</Box>
|
||||||
className={classnames(style.progressBar)}
|
|
||||||
style={{
|
|
||||||
width: `${(passwordScore + 1) * (100 / maxScores)}%`,
|
|
||||||
backgroundColor: progressColor[passwordScore],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,25 @@
|
||||||
import React, { Fragment } from "react";
|
import React, { Fragment } from "react";
|
||||||
|
|
||||||
import { Tooltip, Typography } from "@material-ui/core";
|
import { Tooltip, Typography } from "@mui/material";
|
||||||
import { Variant } from "@material-ui/core/styles/createTypography";
|
import { Variant } from "@mui/material/styles/createTypography";
|
||||||
import { CSSProperties } from "@material-ui/styles";
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
variant: Variant;
|
variant: Variant;
|
||||||
|
|
||||||
value?: string;
|
value?: string;
|
||||||
style?: CSSProperties;
|
|
||||||
|
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
tooltipStyle?: CSSProperties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TypographyWithTooltip(props: Props): JSX.Element {
|
export default function TypographyWithTooltip(props: Props): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{props.tooltip ? (
|
{props.tooltip ? (
|
||||||
<Tooltip title={props.tooltip} style={props.tooltipStyle}>
|
<Tooltip title={props.tooltip}>
|
||||||
<Typography variant={props.variant} style={props.style}>
|
<Typography variant={props.variant}>{props.value}</Typography>
|
||||||
{props.value}
|
|
||||||
</Typography>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<Typography variant={props.variant} style={props.style}>
|
<Typography variant={props.variant}>{props.value}</Typography>
|
||||||
{props.value}
|
|
||||||
</Typography>
|
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { createContext, useContext, useRef } from "react";
|
import { createContext, useContext, useRef } from "react";
|
||||||
|
|
||||||
import { Level } from "@components/ColoredSnackbarContent";
|
import { AlertColor } from "@mui/material";
|
||||||
|
|
||||||
import { Notification } from "@models/Notifications";
|
import { Notification } from "@models/Notifications";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
|
@ -19,7 +20,7 @@ export default NotificationsContext;
|
||||||
export function useNotifications() {
|
export function useNotifications() {
|
||||||
let useNotificationsProps = useContext(NotificationsContext);
|
let useNotificationsProps = useContext(NotificationsContext);
|
||||||
|
|
||||||
const notificationBuilder = (level: Level) => {
|
const notificationBuilder = (level: AlertColor) => {
|
||||||
return (message: string, timeout?: number) => {
|
return (message: string, timeout?: number) => {
|
||||||
useNotificationsProps.setNotification({
|
useNotificationsProps.setNotification({
|
||||||
level,
|
level,
|
||||||
|
|
|
@ -7,8 +7,9 @@ import App from "@root/App";
|
||||||
import * as serviceWorker from "@root/serviceWorker";
|
import * as serviceWorker from "@root/serviceWorker";
|
||||||
import "@i18n/index.ts";
|
import "@i18n/index.ts";
|
||||||
|
|
||||||
|
const nonce = document.head.querySelector("[property=csp-nonce][content]")?.getAttribute("content") || undefined;
|
||||||
const root = createRoot(document.getElementById("root")!);
|
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
|
// If you want your app to work offline and load faster, you can change
|
||||||
// unregister() to register() below. Note this comes with some pitfalls.
|
// unregister() to register() below. Note this comes with some pitfalls.
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import React, { ReactNode, useEffect } from "react";
|
import React, { ReactNode, useEffect } from "react";
|
||||||
|
|
||||||
import { Grid, makeStyles, Container, Link } from "@material-ui/core";
|
import { Grid, Container, Link, Theme } from "@mui/material";
|
||||||
import { grey } from "@material-ui/core/colors";
|
import { grey } from "@mui/material/colors";
|
||||||
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { ReactComponent as UserSvg } from "@assets/images/user.svg";
|
import { ReactComponent as UserSvg } from "@assets/images/user.svg";
|
||||||
|
@ -18,20 +19,22 @@ export interface Props {
|
||||||
showBrand?: boolean;
|
showBrand?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const url = "https://www.authelia.com";
|
||||||
|
|
||||||
const LoginLayout = function (props: Props) {
|
const LoginLayout = function (props: Props) {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const logo = getLogoOverride() ? (
|
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();
|
const { t: translate } = useTranslation();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = `${translate("Login")} - Authelia`;
|
document.title = `${translate("Login")} - Authelia`;
|
||||||
}, [translate]);
|
}, [translate]);
|
||||||
return (
|
return (
|
||||||
<Grid id={props.id} className={style.root} container spacing={0} alignItems="center" justifyContent="center">
|
<Grid id={props.id} className={styles.root} container spacing={0} alignItems="center" justifyContent="center">
|
||||||
<Container maxWidth="xs" className={style.rootContainer}>
|
<Container maxWidth="xs" className={styles.rootContainer}>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
{logo}
|
{logo}
|
||||||
|
@ -50,16 +53,12 @@ const LoginLayout = function (props: Props) {
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
) : null}
|
) : null}
|
||||||
<Grid item xs={12} className={style.body}>
|
<Grid item xs={12} className={styles.body}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Grid>
|
</Grid>
|
||||||
{props.showBrand ? (
|
{props.showBrand ? (
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Link
|
<Link href={url} target="_blank" underline="hover" className={styles.poweredBy}>
|
||||||
href="https://github.com/authelia/authelia"
|
|
||||||
target="_blank"
|
|
||||||
className={style.poweredBy}
|
|
||||||
>
|
|
||||||
{translate("Powered by")} Authelia
|
{translate("Powered by")} Authelia
|
||||||
</Link>
|
</Link>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -72,7 +71,7 @@ const LoginLayout = function (props: Props) {
|
||||||
|
|
||||||
export default LoginLayout;
|
export default LoginLayout;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
root: {
|
root: {
|
||||||
minHeight: "90vh",
|
minHeight: "90vh",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Level } from "@components/ColoredSnackbarContent";
|
import { AlertColor } from "@mui/material";
|
||||||
|
|
||||||
export interface Notification {
|
export interface Notification {
|
||||||
message: string;
|
message: string;
|
||||||
level: Level;
|
level: AlertColor;
|
||||||
timeout: number;
|
timeout: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createTheme } from "@material-ui/core/styles";
|
import { createTheme } from "@mui/material/styles";
|
||||||
|
|
||||||
const Dark = createTheme({
|
const Dark = createTheme({
|
||||||
custom: {
|
custom: {
|
||||||
|
@ -6,10 +6,81 @@ const Dark = createTheme({
|
||||||
loadingBar: "#fff",
|
loadingBar: "#fff",
|
||||||
},
|
},
|
||||||
palette: {
|
palette: {
|
||||||
type: "dark",
|
mode: "dark",
|
||||||
primary: {
|
primary: {
|
||||||
main: "#1976d2",
|
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,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createTheme } from "@material-ui/core/styles";
|
import { createTheme } from "@mui/material/styles";
|
||||||
|
|
||||||
const Grey = createTheme({
|
const Grey = createTheme({
|
||||||
custom: {
|
custom: {
|
||||||
|
@ -6,51 +6,129 @@ const Grey = createTheme({
|
||||||
loadingBar: "#929aa5",
|
loadingBar: "#929aa5",
|
||||||
},
|
},
|
||||||
palette: {
|
palette: {
|
||||||
|
mode: "dark",
|
||||||
primary: {
|
primary: {
|
||||||
main: "#929aa5",
|
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: {
|
background: {
|
||||||
default: "#2f343e",
|
|
||||||
paper: "#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: {
|
MuiCssBaseline: {
|
||||||
"@global": {
|
styleOverrides: {
|
||||||
body: {
|
"@global": {
|
||||||
backgroundColor: "#2f343e",
|
body: {
|
||||||
color: "#929aa5",
|
backgroundColor: "#2f343e",
|
||||||
|
color: "#929aa5",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
MuiOutlinedInput: {
|
MuiOutlinedInput: {
|
||||||
root: {
|
styleOverrides: {
|
||||||
"& $notchedOutline": {
|
root: {
|
||||||
borderColor: "#929aa5",
|
"& $notchedOutline": {
|
||||||
},
|
borderColor: "#929aa5",
|
||||||
"&:hover:not($disabled):not($focused):not($error) $notchedOutline": {
|
},
|
||||||
borderColor: "#929aa5",
|
"&:hover:not($disabled):not($focused):not($error) $notchedOutline": {
|
||||||
borderWidth: 2,
|
borderColor: "#929aa5",
|
||||||
},
|
borderWidth: 2,
|
||||||
"&$focused $notchedOutline": {
|
},
|
||||||
borderColor: "#929aa5",
|
"&$focused $notchedOutline": {
|
||||||
|
borderColor: "#929aa5",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
notchedOutline: {},
|
||||||
},
|
},
|
||||||
notchedOutline: {},
|
|
||||||
},
|
},
|
||||||
MuiCheckbox: {
|
MuiCheckbox: {
|
||||||
root: {
|
styleOverrides: {
|
||||||
color: "#929aa5",
|
root: {
|
||||||
|
color: "#929aa5",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
MuiInputBase: {
|
MuiInputBase: {
|
||||||
input: {
|
styleOverrides: {
|
||||||
color: "#929aa5",
|
input: {
|
||||||
|
color: "#929aa5",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
MuiInputLabel: {
|
MuiInputLabel: {
|
||||||
root: {
|
styleOverrides: {
|
||||||
color: "#929aa5",
|
root: {
|
||||||
|
color: "#929aa5",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createTheme } from "@material-ui/core/styles";
|
import { createTheme } from "@mui/material/styles";
|
||||||
|
|
||||||
const Light = createTheme({
|
const Light = createTheme({
|
||||||
custom: {
|
custom: {
|
||||||
|
@ -6,12 +6,80 @@ const Light = createTheme({
|
||||||
loadingBar: "#000",
|
loadingBar: "#000",
|
||||||
},
|
},
|
||||||
palette: {
|
palette: {
|
||||||
|
mode: "light",
|
||||||
primary: {
|
primary: {
|
||||||
main: "#1976d2",
|
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: {
|
background: {
|
||||||
default: "#fff",
|
|
||||||
paper: "#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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -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 {
|
interface Theme {
|
||||||
custom: {
|
custom: {
|
||||||
icon: React.CSSProperties["color"];
|
icon: React.CSSProperties["color"];
|
||||||
loadingBar: React.CSSProperties["color"];
|
loadingBar: React.CSSProperties["color"];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ThemeOptions {
|
interface ThemeOptions {
|
||||||
custom: {
|
custom?: {
|
||||||
icon: React.CSSProperties["color"];
|
icon?: React.CSSProperties["color"];
|
||||||
loadingBar: 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 Light } from "@themes/Light";
|
||||||
export { default as Dark } from "@themes/Dark";
|
export { default as Dark } from "@themes/Dark";
|
||||||
export { default as Grey } from "@themes/Grey";
|
export { default as Grey } from "@themes/Grey";
|
||||||
|
|
|
@ -2,10 +2,11 @@ import React, { useEffect, useCallback, useState } from "react";
|
||||||
|
|
||||||
import { IconDefinition, faCopy, faKey, faTimesCircle } from "@fortawesome/free-solid-svg-icons";
|
import { IconDefinition, faCopy, faKey, faTimesCircle } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { makeStyles, Typography, Button, IconButton, Link, CircularProgress, TextField } from "@material-ui/core";
|
import { Typography, Button, IconButton, Link, CircularProgress, TextField, Theme } from "@mui/material";
|
||||||
import { red } from "@material-ui/core/colors";
|
import { red } from "@mui/material/colors";
|
||||||
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
import QRCode from "qrcode.react";
|
import { QRCodeSVG } from "qrcode.react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ import { completeTOTPRegistrationProcess } from "@services/RegisterDevice";
|
||||||
import { extractIdentityToken } from "@utils/IdentityToken";
|
import { extractIdentityToken } from "@utils/IdentityToken";
|
||||||
|
|
||||||
const RegisterOneTimePassword = function () {
|
const RegisterOneTimePassword = function () {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
// The secret retrieved from the API is all is ok.
|
// 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) {
|
function SecretButton(text: string | undefined, action: string, icon: IconDefinition) {
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
className={style.secretButtons}
|
className={styles.secretButtons}
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(`${text}`);
|
navigator.clipboard.writeText(`${text}`);
|
||||||
createSuccessNotification(`${action}`);
|
createSuccessNotification(`${action}`);
|
||||||
}}
|
}}
|
||||||
|
size="large"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={icon} />
|
<FontAwesomeIcon icon={icon} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const qrcodeFuzzyStyle = isLoading || hasErrored ? style.fuzzy : undefined;
|
const qrcodeFuzzyStyle = isLoading || hasErrored ? styles.fuzzy : undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoginLayout title={translate("Scan QR Code")}>
|
<LoginLayout title={translate("Scan QR Code")}>
|
||||||
<div className={style.root}>
|
<div className={styles.root}>
|
||||||
<div className={style.googleAuthenticator}>
|
<div className={styles.googleAuthenticator}>
|
||||||
<Typography className={style.googleAuthenticatorText}>
|
<Typography className={styles.googleAuthenticatorText}>
|
||||||
{translate("Need Google Authenticator?")}
|
{translate("Need Google Authenticator?")}
|
||||||
</Typography>
|
</Typography>
|
||||||
<AppStoreBadges
|
<AppStoreBadges
|
||||||
iconSize={128}
|
iconSize={128}
|
||||||
targetBlank
|
targetBlank
|
||||||
className={style.googleAuthenticatorBadges}
|
className={styles.googleAuthenticatorBadges}
|
||||||
googlePlayLink={GoogleAuthenticator.googlePlay}
|
googlePlayLink={GoogleAuthenticator.googlePlay}
|
||||||
appleStoreLink={GoogleAuthenticator.appleStore}
|
appleStoreLink={GoogleAuthenticator.appleStore}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={classnames(qrcodeFuzzyStyle, style.qrcodeContainer)}>
|
<div className={classnames(qrcodeFuzzyStyle, styles.qrcodeContainer)}>
|
||||||
<Link href={secretURL}>
|
<Link href={secretURL} underline="hover">
|
||||||
<QRCode value={secretURL} className={style.qrcode} size={256} />
|
<QRCodeSVG value={secretURL} className={styles.qrcode} size={256} />
|
||||||
{!hasErrored && isLoading ? <CircularProgress className={style.loader} size={128} /> : null}
|
{!hasErrored && isLoading ? <CircularProgress className={styles.loader} size={128} /> : null}
|
||||||
{hasErrored ? <FontAwesomeIcon className={style.failureIcon} icon={faTimesCircle} /> : null}
|
{hasErrored ? <FontAwesomeIcon className={styles.failureIcon} icon={faTimesCircle} /> : null}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -112,7 +114,7 @@ const RegisterOneTimePassword = function () {
|
||||||
<TextField
|
<TextField
|
||||||
id="secret-url"
|
id="secret-url"
|
||||||
label={translate("Secret")}
|
label={translate("Secret")}
|
||||||
className={style.secret}
|
className={styles.secret}
|
||||||
value={secretURL}
|
value={secretURL}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
|
@ -129,7 +131,7 @@ const RegisterOneTimePassword = function () {
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
className={style.doneButton}
|
className={styles.doneButton}
|
||||||
onClick={handleDoneClick}
|
onClick={handleDoneClick}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
>
|
>
|
||||||
|
@ -142,7 +144,7 @@ const RegisterOneTimePassword = function () {
|
||||||
|
|
||||||
export default RegisterOneTimePassword;
|
export default RegisterOneTimePassword;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
root: {
|
root: {
|
||||||
paddingTop: theme.spacing(4),
|
paddingTop: theme.spacing(4),
|
||||||
paddingBottom: theme.spacing(4),
|
paddingBottom: theme.spacing(4),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
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 { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import FingerTouchIcon from "@components/FingerTouchIcon";
|
import FingerTouchIcon from "@components/FingerTouchIcon";
|
||||||
|
@ -12,7 +13,7 @@ import { performAttestationCeremony } from "@services/Webauthn";
|
||||||
import { extractIdentityToken } from "@utils/IdentityToken";
|
import { extractIdentityToken } from "@utils/IdentityToken";
|
||||||
|
|
||||||
const RegisterWebauthn = function () {
|
const RegisterWebauthn = function () {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { createErrorNotification } = useNotifications();
|
const { createErrorNotification } = useNotifications();
|
||||||
|
@ -84,10 +85,10 @@ const RegisterWebauthn = function () {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoginLayout title="Touch Security Key">
|
<LoginLayout title="Touch Security Key">
|
||||||
<div className={style.icon}>
|
<div className={styles.icon}>
|
||||||
<FingerTouchIcon size={64} animated />
|
<FingerTouchIcon size={64} animated />
|
||||||
</div>
|
</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}>
|
<Button color="primary" onClick={handleBackClick}>
|
||||||
Retry
|
Retry
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -100,7 +101,7 @@ const RegisterWebauthn = function () {
|
||||||
|
|
||||||
export default RegisterWebauthn;
|
export default RegisterWebauthn;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
icon: {
|
icon: {
|
||||||
paddingTop: theme.spacing(4),
|
paddingTop: theme.spacing(4),
|
||||||
paddingBottom: theme.spacing(4),
|
paddingBottom: theme.spacing(4),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from "react";
|
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";
|
import ReactLoading from "react-loading";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
@ -9,9 +10,11 @@ export interface Props {
|
||||||
|
|
||||||
const BaseLoadingPage = function (props: Props) {
|
const BaseLoadingPage = function (props: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const styles = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container alignItems="center" justifyContent="center" style={{ minHeight: "100vh" }}>
|
<Grid container className={styles.gridOuter}>
|
||||||
<Grid item style={{ textAlign: "center", display: "inline-block" }}>
|
<Grid item className={styles.gridInner}>
|
||||||
<ReactLoading width={64} height={64} color={theme.custom.loadingBar} type="bars" />
|
<ReactLoading width={64} height={64} color={theme.custom.loadingBar} type="bars" />
|
||||||
<Typography>{props.message}...</Typography>
|
<Typography>{props.message}...</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -20,3 +23,15 @@ const BaseLoadingPage = function (props: Props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default BaseLoadingPage;
|
export default BaseLoadingPage;
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
|
gridOuter: {
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
minHeight: "100vh",
|
||||||
|
},
|
||||||
|
gridInner: {
|
||||||
|
textAlign: "center",
|
||||||
|
display: "inline-block",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import React from "react";
|
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 { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import SuccessIcon from "@components/SuccessIcon";
|
import SuccessIcon from "@components/SuccessIcon";
|
||||||
|
|
||||||
const Authenticated = function () {
|
const Authenticated = function () {
|
||||||
const classes = useStyles();
|
const styles = useStyles();
|
||||||
const { t: translate } = useTranslation();
|
const { t: translate } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div id="authenticated-stage">
|
<div id="authenticated-stage">
|
||||||
<div className={classes.iconContainer}>
|
<div className={styles.iconContainer}>
|
||||||
<SuccessIcon />
|
<SuccessIcon />
|
||||||
</div>
|
</div>
|
||||||
<Typography>{translate("Authenticated")}</Typography>
|
<Typography>{translate("Authenticated")}</Typography>
|
||||||
|
@ -20,7 +21,7 @@ const Authenticated = function () {
|
||||||
|
|
||||||
export default Authenticated;
|
export default Authenticated;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
iconContainer: {
|
iconContainer: {
|
||||||
marginBottom: theme.spacing(2),
|
marginBottom: theme.spacing(2),
|
||||||
flex: "0 0 100%",
|
flex: "0 0 100%",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from "react";
|
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 { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const AuthenticatedView = function (props: Props) {
|
const AuthenticatedView = function (props: Props) {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { t: translate } = useTranslation();
|
const { t: translate } = useTranslation();
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ const AuthenticatedView = function (props: Props) {
|
||||||
{translate("Logout")}
|
{translate("Logout")}
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} className={style.mainContainer}>
|
<Grid item xs={12} className={styles.mainContainer}>
|
||||||
<Authenticated />
|
<Authenticated />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -39,7 +40,7 @@ const AuthenticatedView = function (props: Props) {
|
||||||
|
|
||||||
export default AuthenticatedView;
|
export default AuthenticatedView;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
mainContainer: {
|
mainContainer: {
|
||||||
border: "1px solid #d6d6d6",
|
border: "1px solid #d6d6d6",
|
||||||
borderRadius: "10px",
|
borderRadius: "10px",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useEffect, Fragment, ReactNode, useState } from "react";
|
import React, { useEffect, Fragment, ReactNode, useState } from "react";
|
||||||
|
|
||||||
|
import { AccountBox, CheckBox, Contacts, Drafts, Group } from "@mui/icons-material";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Grid,
|
Grid,
|
||||||
|
@ -9,11 +10,11 @@ import {
|
||||||
ListItemText,
|
ListItemText,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
makeStyles,
|
|
||||||
Checkbox,
|
Checkbox,
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
} from "@material-ui/core";
|
Theme,
|
||||||
import { AccountBox, CheckBox, Contacts, Drafts, Group } from "@material-ui/icons";
|
} from "@mui/material";
|
||||||
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ function scopeNameToAvatar(id: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConsentView = function (props: Props) {
|
const ConsentView = function (props: Props) {
|
||||||
const classes = useStyles();
|
const styles = useStyles();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const redirect = useRedirector();
|
const redirect = useRedirector();
|
||||||
const { createErrorNotification, resetNotification } = useNotifications();
|
const { createErrorNotification, resetNotification } = useNotifications();
|
||||||
|
@ -137,7 +138,7 @@ const ConsentView = function (props: Props) {
|
||||||
"Client ID: " + resp?.client_id
|
"Client ID: " + resp?.client_id
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Typography className={classes.clientDescription}>
|
<Typography className={styles.clientDescription}>
|
||||||
{resp !== undefined && resp.client_description !== ""
|
{resp !== undefined && resp.client_description !== ""
|
||||||
? resp.client_description
|
? resp.client_description
|
||||||
: resp?.client_id}
|
: resp?.client_id}
|
||||||
|
@ -149,8 +150,8 @@ const ConsentView = function (props: Props) {
|
||||||
<div>{translate("The above application is requesting the following permissions")}:</div>
|
<div>{translate("The above application is requesting the following permissions")}:</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<div className={classes.scopesListContainer}>
|
<div className={styles.scopesListContainer}>
|
||||||
<List className={classes.scopesList}>
|
<List className={styles.scopesList}>
|
||||||
{resp?.scopes.map((scope: string) => (
|
{resp?.scopes.map((scope: string) => (
|
||||||
<Tooltip title={"Scope " + scope}>
|
<Tooltip title={"Scope " + scope}>
|
||||||
<ListItem id={"scope-" + scope} dense>
|
<ListItem id={"scope-" + scope} dense>
|
||||||
|
@ -180,7 +181,7 @@ const ConsentView = function (props: Props) {
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
className={classes.preConfigure}
|
className={styles.preConfigure}
|
||||||
label={translate("Remember Consent")}
|
label={translate("Remember Consent")}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -191,7 +192,7 @@ const ConsentView = function (props: Props) {
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
<Button
|
<Button
|
||||||
id="accept-button"
|
id="accept-button"
|
||||||
className={classes.button}
|
className={styles.button}
|
||||||
disabled={!resp}
|
disabled={!resp}
|
||||||
onClick={handleAcceptConsent}
|
onClick={handleAcceptConsent}
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -203,7 +204,7 @@ const ConsentView = function (props: Props) {
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
<Button
|
<Button
|
||||||
id="deny-button"
|
id="deny-button"
|
||||||
className={classes.button}
|
className={styles.button}
|
||||||
disabled={!resp}
|
disabled={!resp}
|
||||||
onClick={handleRejectConsent}
|
onClick={handleRejectConsent}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
|
@ -220,7 +221,7 @@ const ConsentView = function (props: Props) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
container: {
|
container: {
|
||||||
paddingTop: theme.spacing(4),
|
paddingTop: theme.spacing(4),
|
||||||
paddingBottom: theme.spacing(4),
|
paddingBottom: theme.spacing(4),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
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 classnames from "classnames";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
@ -29,7 +30,7 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const FirstFactorForm = function (props: Props) {
|
const FirstFactorForm = function (props: Props) {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const redirectionURL = useRedirectionURL();
|
const redirectionURL = useRedirectionURL();
|
||||||
const requestMethod = useRequestMethod();
|
const requestMethod = useRequestMethod();
|
||||||
|
@ -170,7 +171,7 @@ const FirstFactorForm = function (props: Props) {
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
{props.rememberMe ? (
|
{props.rememberMe ? (
|
||||||
<Grid item xs={12} className={classnames(style.actionRow)}>
|
<Grid item xs={12} className={classnames(styles.actionRow)}>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
@ -192,7 +193,7 @@ const FirstFactorForm = function (props: Props) {
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
className={style.rememberMe}
|
className={styles.rememberMe}
|
||||||
label={translate("Remember me")}
|
label={translate("Remember me")}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -210,12 +211,13 @@ const FirstFactorForm = function (props: Props) {
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
{props.resetPassword ? (
|
{props.resetPassword ? (
|
||||||
<Grid item xs={12} className={classnames(style.actionRow, style.flexEnd)}>
|
<Grid item xs={12} className={classnames(styles.actionRow, styles.flexEnd)}>
|
||||||
<Link
|
<Link
|
||||||
id="reset-password-button"
|
id="reset-password-button"
|
||||||
component="button"
|
component="button"
|
||||||
onClick={handleResetPasswordClick}
|
onClick={handleResetPasswordClick}
|
||||||
className={style.resetLink}
|
className={styles.resetLink}
|
||||||
|
underline="hover"
|
||||||
>
|
>
|
||||||
{translate("Reset password?")}
|
{translate("Reset password?")}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -228,7 +230,7 @@ const FirstFactorForm = function (props: Props) {
|
||||||
|
|
||||||
export default FirstFactorForm;
|
export default FirstFactorForm;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
actionRow: {
|
actionRow: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { ReactNode, useState } from "react";
|
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";
|
import PushNotificationIcon from "@components/PushNotificationIcon";
|
||||||
|
|
||||||
|
@ -102,7 +103,7 @@ interface DeviceItemProps {
|
||||||
function DeviceItem(props: DeviceItemProps) {
|
function DeviceItem(props: DeviceItemProps) {
|
||||||
const className = "device-option-" + props.id;
|
const className = "device-option-" + props.id;
|
||||||
const idName = "device-" + props.device.id;
|
const idName = "device-" + props.device.id;
|
||||||
const style = makeStyles((theme) => ({
|
const style = makeStyles((theme: Theme) => ({
|
||||||
item: {
|
item: {
|
||||||
paddingTop: theme.spacing(4),
|
paddingTop: theme.spacing(4),
|
||||||
paddingBottom: theme.spacing(4),
|
paddingBottom: theme.spacing(4),
|
||||||
|
@ -147,7 +148,7 @@ interface MethodItemProps {
|
||||||
function MethodItem(props: MethodItemProps) {
|
function MethodItem(props: MethodItemProps) {
|
||||||
const className = "method-option-" + props.id;
|
const className = "method-option-" + props.id;
|
||||||
const idName = "method-" + props.method;
|
const idName = "method-" + props.method;
|
||||||
const style = makeStyles((theme) => ({
|
const style = makeStyles((theme: Theme) => ({
|
||||||
item: {
|
item: {
|
||||||
paddingTop: theme.spacing(4),
|
paddingTop: theme.spacing(4),
|
||||||
paddingBottom: theme.spacing(4),
|
paddingBottom: theme.spacing(4),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { ReactNode } from "react";
|
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";
|
import classnames from "classnames";
|
||||||
|
|
||||||
interface IconWithContextProps {
|
interface IconWithContextProps {
|
||||||
|
@ -12,7 +13,7 @@ interface IconWithContextProps {
|
||||||
|
|
||||||
const IconWithContext = function (props: IconWithContextProps) {
|
const IconWithContext = function (props: IconWithContextProps) {
|
||||||
const iconSize = 64;
|
const iconSize = 64;
|
||||||
const style = makeStyles((theme) => ({
|
const styles = makeStyles((theme: Theme) => ({
|
||||||
root: {},
|
root: {},
|
||||||
iconContainer: {
|
iconContainer: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -29,11 +30,11 @@ const IconWithContext = function (props: IconWithContextProps) {
|
||||||
}))();
|
}))();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames(props.className, style.root)}>
|
<div className={classnames(props.className, styles.root)}>
|
||||||
<div className={style.iconContainer}>
|
<div className={styles.iconContainer}>
|
||||||
<div className={style.icon}>{props.icon}</div>
|
<div className={styles.icon}>{props.icon}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.context}>{props.children}</div>
|
<div className={styles.context}>{props.children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { ReactNode, Fragment } from "react";
|
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 classnames from "classnames";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DefaultMethodContainer = function (props: Props) {
|
const DefaultMethodContainer = function (props: Props) {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const { t: translate } = useTranslation();
|
const { t: translate } = useTranslation();
|
||||||
const registerMessage = props.registered
|
const registerMessage = props.registered
|
||||||
? props.title === "Push Notification"
|
? props.title === "Push Notification"
|
||||||
|
@ -56,17 +57,17 @@ const DefaultMethodContainer = function (props: Props) {
|
||||||
return (
|
return (
|
||||||
<div id={props.id}>
|
<div id={props.id}>
|
||||||
<Typography variant="h6">{props.title}</Typography>
|
<Typography variant="h6">{props.title}</Typography>
|
||||||
<div className={classnames(style.container, stateClass)} id="2fa-container">
|
<div className={classnames(styles.container, stateClass)} id="2fa-container">
|
||||||
<div className={style.containerFlex}>{container}</div>
|
<div className={styles.containerFlex}>{container}</div>
|
||||||
</div>
|
</div>
|
||||||
{props.onSelectClick && props.registered ? (
|
{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}
|
{selectMessage}
|
||||||
</Link>
|
</Link>
|
||||||
) : null}
|
) : null}
|
||||||
{(props.onRegisterClick && props.title !== "Push Notification") ||
|
{(props.onRegisterClick && props.title !== "Push Notification") ||
|
||||||
(props.onRegisterClick && props.title === "Push Notification" && props.duoSelfEnrollment) ? (
|
(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}
|
{registerMessage}
|
||||||
</Link>
|
</Link>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -76,7 +77,7 @@ const DefaultMethodContainer = function (props: Props) {
|
||||||
|
|
||||||
export default DefaultMethodContainer;
|
export default DefaultMethodContainer;
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
container: {
|
container: {
|
||||||
height: "200px",
|
height: "200px",
|
||||||
},
|
},
|
||||||
|
@ -89,6 +90,16 @@ const useStyles = makeStyles(() => ({
|
||||||
alignContent: "center",
|
alignContent: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
},
|
},
|
||||||
|
containerMethod: {
|
||||||
|
marginBottom: theme.spacing(2),
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
marginBottom: theme.spacing(2),
|
||||||
|
flex: "0 0 100%",
|
||||||
|
},
|
||||||
|
infoTypography: {
|
||||||
|
color: "#5858ff",
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface NotRegisteredContainerProps {
|
interface NotRegisteredContainerProps {
|
||||||
|
@ -98,16 +109,17 @@ interface NotRegisteredContainerProps {
|
||||||
|
|
||||||
function NotRegisteredContainer(props: NotRegisteredContainerProps) {
|
function NotRegisteredContainer(props: NotRegisteredContainerProps) {
|
||||||
const { t: translate } = useTranslation();
|
const { t: translate } = useTranslation();
|
||||||
const theme = useTheme();
|
const styles = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div style={{ marginBottom: theme.spacing(2), flex: "0 0 100%" }}>
|
<Box className={styles.info}>
|
||||||
<InformationIcon />
|
<InformationIcon />
|
||||||
</div>
|
</Box>
|
||||||
<Typography style={{ color: "#5858ff" }}>
|
<Typography className={styles.infoTypography}>
|
||||||
{translate("The resource you're attempting to access requires two-factor authentication")}
|
{translate("The resource you're attempting to access requires two-factor authentication")}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography style={{ color: "#5858ff" }}>
|
<Typography className={styles.infoTypography}>
|
||||||
{props.title === "Push Notification"
|
{props.title === "Push Notification"
|
||||||
? props.duoSelfEnrollment
|
? props.duoSelfEnrollment
|
||||||
? translate("Register your first device by clicking on the link below")
|
? translate("Register your first device by clicking on the link below")
|
||||||
|
@ -124,10 +136,11 @@ interface MethodContainerProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function MethodContainer(props: MethodContainerProps) {
|
function MethodContainer(props: MethodContainerProps) {
|
||||||
const theme = useTheme();
|
const styles = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div style={{ marginBottom: theme.spacing(2) }}>{props.children}</div>
|
<Box className={styles.containerMethod}>{props.children}</Box>
|
||||||
<Typography>{props.explanation}</Typography>
|
<Typography>{props.explanation}</Typography>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,15 +1,7 @@
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
import {
|
import { Dialog, Grid, DialogContent, Button, DialogActions, Typography, useTheme, Theme } from "@mui/material";
|
||||||
Dialog,
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
Grid,
|
|
||||||
makeStyles,
|
|
||||||
DialogContent,
|
|
||||||
Button,
|
|
||||||
DialogActions,
|
|
||||||
Typography,
|
|
||||||
useTheme,
|
|
||||||
} from "@material-ui/core";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import FingerTouchIcon from "@components/FingerTouchIcon";
|
import FingerTouchIcon from "@components/FingerTouchIcon";
|
||||||
|
@ -27,7 +19,7 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const MethodSelectionDialog = function (props: Props) {
|
const MethodSelectionDialog = function (props: Props) {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t: translate } = useTranslation();
|
const { t: translate } = useTranslation();
|
||||||
|
|
||||||
|
@ -36,7 +28,7 @@ const MethodSelectionDialog = function (props: Props) {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={props.open} className={style.root} onClose={props.onClose}>
|
<Dialog open={props.open} className={styles.root} onClose={props.onClose}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Grid container justifyContent="center" spacing={1} id="methods-dialog">
|
<Grid container justifyContent="center" spacing={1} id="methods-dialog">
|
||||||
{props.methods.has(SecondFactorMethod.TOTP) ? (
|
{props.methods.has(SecondFactorMethod.TOTP) ? (
|
||||||
|
@ -76,7 +68,7 @@ const MethodSelectionDialog = function (props: Props) {
|
||||||
|
|
||||||
export default MethodSelectionDialog;
|
export default MethodSelectionDialog;
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
root: {
|
root: {
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
},
|
},
|
||||||
|
@ -91,7 +83,7 @@ interface MethodItemProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function MethodItem(props: MethodItemProps) {
|
function MethodItem(props: MethodItemProps) {
|
||||||
const style = makeStyles((theme) => ({
|
const style = makeStyles((theme: Theme) => ({
|
||||||
item: {
|
item: {
|
||||||
paddingTop: theme.spacing(4),
|
paddingTop: theme.spacing(4),
|
||||||
paddingBottom: theme.spacing(4),
|
paddingBottom: theme.spacing(4),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { Fragment } from "react";
|
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 classnames from "classnames";
|
||||||
import OtpInput from "react-otp-input";
|
import OtpInput from "react-otp-input";
|
||||||
|
|
||||||
|
@ -20,11 +21,11 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const OTPDial = function (props: Props) {
|
const OTPDial = function (props: Props) {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconWithContext icon={<Icon state={props.state} period={props.period} />}>
|
<IconWithContext icon={<Icon state={props.state} period={props.period} />}>
|
||||||
<span className={style.otpInput} id="otp-input">
|
<span className={styles.otpInput} id="otp-input">
|
||||||
<OtpInput
|
<OtpInput
|
||||||
shouldAutoFocus
|
shouldAutoFocus
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
|
@ -33,7 +34,10 @@ const OTPDial = function (props: Props) {
|
||||||
isDisabled={props.state === State.InProgress || props.state === State.Success}
|
isDisabled={props.state === State.InProgress || props.state === State.Success}
|
||||||
isInputNum
|
isInputNum
|
||||||
hasErrored={props.state === State.Failure}
|
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>
|
</span>
|
||||||
</IconWithContext>
|
</IconWithContext>
|
||||||
|
@ -42,7 +46,7 @@ const OTPDial = function (props: Props) {
|
||||||
|
|
||||||
export default OTPDial;
|
export default OTPDial;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
timeProgress: {},
|
timeProgress: {},
|
||||||
register: {
|
register: {
|
||||||
marginTop: theme.spacing(),
|
marginTop: theme.spacing(),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useEffect, useCallback, useRef, useState, ReactNode } from "react";
|
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 FailureIcon from "@components/FailureIcon";
|
||||||
import PushNotificationIcon from "@components/PushNotificationIcon";
|
import PushNotificationIcon from "@components/PushNotificationIcon";
|
||||||
|
@ -40,7 +41,7 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const PushNotificationMethod = function (props: Props) {
|
const PushNotificationMethod = function (props: Props) {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const [state, setState] = useState(State.SignInInProgress);
|
const [state, setState] = useState(State.SignInInProgress);
|
||||||
const redirectionURL = useRedirectionURL();
|
const redirectionURL = useRedirectionURL();
|
||||||
const mounted = useIsMountedRef();
|
const mounted = useIsMountedRef();
|
||||||
|
@ -216,7 +217,7 @@ const PushNotificationMethod = function (props: Props) {
|
||||||
onSelectClick={fetchDuoDevicesFunc}
|
onSelectClick={fetchDuoDevicesFunc}
|
||||||
onRegisterClick={() => window.open(enroll_url, "_blank")}
|
onRegisterClick={() => window.open(enroll_url, "_blank")}
|
||||||
>
|
>
|
||||||
<div className={style.icon}>{icon}</div>
|
<div className={styles.icon}>{icon}</div>
|
||||||
<div className={state !== State.Failure ? "hidden" : ""}>
|
<div className={state !== State.Failure ? "hidden" : ""}>
|
||||||
<Button color="secondary" onClick={signInFunc}>
|
<Button color="secondary" onClick={signInFunc}>
|
||||||
Retry
|
Retry
|
||||||
|
@ -228,7 +229,7 @@ const PushNotificationMethod = function (props: Props) {
|
||||||
|
|
||||||
export default PushNotificationMethod;
|
export default PushNotificationMethod;
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
icon: {
|
icon: {
|
||||||
width: "64px",
|
width: "64px",
|
||||||
height: "64px",
|
height: "64px",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useState, useEffect } from "react";
|
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 { useTranslation } from "react-i18next";
|
||||||
import { Route, Routes, useNavigate } from "react-router-dom";
|
import { Route, Routes, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const SecondFactorForm = function (props: Props) {
|
const SecondFactorForm = function (props: Props) {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [methodSelectionOpen, setMethodSelectionOpen] = useState(false);
|
const [methodSelectionOpen, setMethodSelectionOpen] = useState(false);
|
||||||
const { createInfoNotification, createErrorNotification } = useNotifications();
|
const { createInfoNotification, createErrorNotification } = useNotifications();
|
||||||
|
@ -106,7 +107,7 @@ const SecondFactorForm = function (props: Props) {
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} className={style.methodContainer}>
|
<Grid item xs={12} className={styles.methodContainer}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
path={SecondFactorTOTPSubRoute}
|
path={SecondFactorTOTPSubRoute}
|
||||||
|
@ -159,7 +160,7 @@ const SecondFactorForm = function (props: Props) {
|
||||||
|
|
||||||
export default SecondFactorForm;
|
export default SecondFactorForm;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
methodContainer: {
|
methodContainer: {
|
||||||
border: "1px solid #d6d6d6",
|
border: "1px solid #d6d6d6",
|
||||||
borderRadius: "10px",
|
borderRadius: "10px",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Fragment, useCallback, useEffect, useRef, useState } from "react";
|
import React, { Fragment, useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
import { Button, makeStyles, useTheme } from "@material-ui/core";
|
import { Button, Theme, useTheme } from "@mui/material";
|
||||||
import { CSSProperties } from "@material-ui/styles";
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
|
|
||||||
import FailureIcon from "@components/FailureIcon";
|
import FailureIcon from "@components/FailureIcon";
|
||||||
import FingerTouchIcon from "@components/FingerTouchIcon";
|
import FingerTouchIcon from "@components/FingerTouchIcon";
|
||||||
|
@ -38,7 +38,7 @@ export interface Props {
|
||||||
const WebauthnMethod = function (props: Props) {
|
const WebauthnMethod = function (props: Props) {
|
||||||
const signInTimeout = 30;
|
const signInTimeout = 30;
|
||||||
const [state, setState] = useState(State.WaitTouch);
|
const [state, setState] = useState(State.WaitTouch);
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const redirectionURL = useRedirectionURL();
|
const redirectionURL = useRedirectionURL();
|
||||||
const mounted = useIsMountedRef();
|
const mounted = useIsMountedRef();
|
||||||
const [timerPercent, triggerTimer] = useTimer(signInTimeout * 1000 - 500);
|
const [timerPercent, triggerTimer] = useTimer(signInTimeout * 1000 - 500);
|
||||||
|
@ -162,7 +162,7 @@ const WebauthnMethod = function (props: Props) {
|
||||||
state={methodState}
|
state={methodState}
|
||||||
onRegisterClick={props.onRegisterClick}
|
onRegisterClick={props.onRegisterClick}
|
||||||
>
|
>
|
||||||
<div className={style.icon}>
|
<div className={styles.icon}>
|
||||||
<Icon state={state} timer={timerPercent} onRetryClick={doInitiateSignIn} />
|
<Icon state={state} timer={timerPercent} onRetryClick={doInitiateSignIn} />
|
||||||
</div>
|
</div>
|
||||||
</MethodContainer>
|
</MethodContainer>
|
||||||
|
@ -171,7 +171,7 @@ const WebauthnMethod = function (props: Props) {
|
||||||
|
|
||||||
export default WebauthnMethod;
|
export default WebauthnMethod;
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
icon: {
|
icon: {
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
},
|
},
|
||||||
|
@ -188,16 +188,18 @@ function Icon(props: IconProps) {
|
||||||
const state = props.state as State;
|
const state = props.state as State;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const progressBarStyle: CSSProperties = {
|
const styles = makeStyles((theme: Theme) => ({
|
||||||
marginTop: theme.spacing(),
|
progressBar: {
|
||||||
};
|
marginTop: theme.spacing(),
|
||||||
|
},
|
||||||
|
}))();
|
||||||
|
|
||||||
const touch = (
|
const touch = (
|
||||||
<IconWithContext
|
<IconWithContext
|
||||||
icon={<FingerTouchIcon size={64} animated strong />}
|
icon={<FingerTouchIcon size={64} animated strong />}
|
||||||
className={state === State.WaitTouch ? undefined : "hidden"}
|
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>
|
</IconWithContext>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useEffect, useCallback, useState } from "react";
|
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 { useTranslation } from "react-i18next";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate } from "react-router-dom";
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ export interface Props {}
|
||||||
|
|
||||||
const SignOut = function (props: Props) {
|
const SignOut = function (props: Props) {
|
||||||
const mounted = useIsMountedRef();
|
const mounted = useIsMountedRef();
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const { createErrorNotification } = useNotifications();
|
const { createErrorNotification } = useNotifications();
|
||||||
const redirectionURL = useRedirectionURL();
|
const redirectionURL = useRedirectionURL();
|
||||||
const redirector = useRedirector();
|
const redirector = useRedirector();
|
||||||
|
@ -56,14 +57,14 @@ const SignOut = function (props: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoginLayout title={translate("Sign out")}>
|
<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>
|
</LoginLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SignOut;
|
export default SignOut;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
typo: {
|
typo: {
|
||||||
padding: theme.spacing(),
|
padding: theme.spacing(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useState } from "react";
|
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 { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ import LoginLayout from "@layouts/LoginLayout";
|
||||||
import { initiateResetPasswordProcess } from "@services/ResetPassword";
|
import { initiateResetPasswordProcess } from "@services/ResetPassword";
|
||||||
|
|
||||||
const ResetPasswordStep1 = function () {
|
const ResetPasswordStep1 = function () {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
const { createInfoNotification, createErrorNotification } = useNotifications();
|
const { createInfoNotification, createErrorNotification } = useNotifications();
|
||||||
|
@ -42,7 +43,7 @@ const ResetPasswordStep1 = function () {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoginLayout title={translate("Reset password")} id="reset-password-step1-stage">
|
<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}>
|
<Grid item xs={12}>
|
||||||
<FixedTextField
|
<FixedTextField
|
||||||
id="username-textfield"
|
id="username-textfield"
|
||||||
|
@ -83,7 +84,7 @@ const ResetPasswordStep1 = function () {
|
||||||
|
|
||||||
export default ResetPasswordStep1;
|
export default ResetPasswordStep1;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
root: {
|
root: {
|
||||||
marginTop: theme.spacing(2),
|
marginTop: theme.spacing(2),
|
||||||
marginBottom: theme.spacing(2),
|
marginBottom: theme.spacing(2),
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
import { Button, Grid, IconButton, InputAdornment, makeStyles } from "@material-ui/core";
|
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
||||||
import { Visibility, VisibilityOff } from "@material-ui/icons";
|
import { Button, Grid, IconButton, InputAdornment, Theme } from "@mui/material";
|
||||||
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
@ -17,7 +18,7 @@ import { completeResetPasswordProcess, resetPassword } from "@services/ResetPass
|
||||||
import { extractIdentityToken } from "@utils/IdentityToken";
|
import { extractIdentityToken } from "@utils/IdentityToken";
|
||||||
|
|
||||||
const ResetPasswordStep2 = function () {
|
const ResetPasswordStep2 = function () {
|
||||||
const style = useStyles();
|
const styles = useStyles();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [formDisabled, setFormDisabled] = useState(true);
|
const [formDisabled, setFormDisabled] = useState(true);
|
||||||
const [password1, setPassword1] = useState("");
|
const [password1, setPassword1] = useState("");
|
||||||
|
@ -110,7 +111,7 @@ const ResetPasswordStep2 = function () {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoginLayout title={translate("Enter new password")} id="reset-password-step2-stage">
|
<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}>
|
<Grid item xs={12}>
|
||||||
<FixedTextField
|
<FixedTextField
|
||||||
id="password1-textfield"
|
id="password1-textfield"
|
||||||
|
@ -121,7 +122,7 @@ const ResetPasswordStep2 = function () {
|
||||||
disabled={formDisabled}
|
disabled={formDisabled}
|
||||||
onChange={(e) => setPassword1(e.target.value)}
|
onChange={(e) => setPassword1(e.target.value)}
|
||||||
error={errorPassword1}
|
error={errorPassword1}
|
||||||
className={classnames(style.fullWidth)}
|
className={classnames(styles.fullWidth)}
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
|
@ -130,6 +131,7 @@ const ResetPasswordStep2 = function () {
|
||||||
aria-label="toggle password visibility"
|
aria-label="toggle password visibility"
|
||||||
onClick={(e) => setShowPassword(!showPassword)}
|
onClick={(e) => setShowPassword(!showPassword)}
|
||||||
edge="end"
|
edge="end"
|
||||||
|
size="large"
|
||||||
>
|
>
|
||||||
{showPassword ? <VisibilityOff></VisibilityOff> : <Visibility></Visibility>}
|
{showPassword ? <VisibilityOff></VisibilityOff> : <Visibility></Visibility>}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
@ -157,7 +159,7 @@ const ResetPasswordStep2 = function () {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={classnames(style.fullWidth)}
|
className={classnames(styles.fullWidth)}
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -169,7 +171,7 @@ const ResetPasswordStep2 = function () {
|
||||||
name="password1"
|
name="password1"
|
||||||
disabled={formDisabled}
|
disabled={formDisabled}
|
||||||
onClick={handleResetClick}
|
onClick={handleResetClick}
|
||||||
className={style.fullWidth}
|
className={styles.fullWidth}
|
||||||
>
|
>
|
||||||
{translate("Reset")}
|
{translate("Reset")}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -181,7 +183,7 @@ const ResetPasswordStep2 = function () {
|
||||||
color="primary"
|
color="primary"
|
||||||
name="password2"
|
name="password2"
|
||||||
onClick={handleCancelClick}
|
onClick={handleCancelClick}
|
||||||
className={style.fullWidth}
|
className={styles.fullWidth}
|
||||||
>
|
>
|
||||||
{translate("Cancel")}
|
{translate("Cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -193,7 +195,7 @@ const ResetPasswordStep2 = function () {
|
||||||
|
|
||||||
export default ResetPasswordStep2;
|
export default ResetPasswordStep2;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
root: {
|
root: {
|
||||||
marginTop: theme.spacing(2),
|
marginTop: theme.spacing(2),
|
||||||
marginBottom: theme.spacing(2),
|
marginBottom: theme.spacing(2),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user