fix login
This commit is contained in:
@@ -4,13 +4,13 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { Input } from '../../components/ui/Controls/Input';
|
import { Input } from '../../components/ui/Controls/Input';
|
||||||
import { validateRequiredValue } from '../../helpers/validators';
|
import { validateRequiredValue } from '../../helpers/validators';
|
||||||
|
|
||||||
type FormValues = {
|
export type LoginFormValues = {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type LoginFormProps = {
|
type LoginFormProps = {
|
||||||
onSubmit: (data: FormValues) => void;
|
onSubmit: (data: LoginFormValues) => void;
|
||||||
processing: boolean;
|
processing: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ const Form = ({ onSubmit, processing }: LoginFormProps) => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
formState: { isValid },
|
formState: { isValid },
|
||||||
} = useForm<FormValues>({
|
} = useForm<LoginFormValues>({
|
||||||
mode: 'onBlur',
|
mode: 'onBlur',
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
username: '',
|
username: '',
|
||||||
|
|||||||
@@ -1,95 +1,68 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import flow from 'lodash/flow';
|
import { Trans } from 'react-i18next';
|
||||||
import { withTranslation, Trans } from 'react-i18next';
|
|
||||||
|
|
||||||
import * as actionCreators from '../../actions/login';
|
import * as actionCreators from '../../actions/login';
|
||||||
|
|
||||||
import { Logo } from '../../components/ui/svg/logo';
|
import { Logo } from '../../components/ui/svg/logo';
|
||||||
|
|
||||||
import Toasts from '../../components/Toasts';
|
import Toasts from '../../components/Toasts';
|
||||||
|
|
||||||
import Footer from '../../components/ui/Footer';
|
import Footer from '../../components/ui/Footer';
|
||||||
|
|
||||||
import Icons from '../../components/ui/Icons';
|
import Icons from '../../components/ui/Icons';
|
||||||
|
import Form, { LoginFormValues } from './Form';
|
||||||
import Form from './Form';
|
|
||||||
|
|
||||||
import './Login.css';
|
import './Login.css';
|
||||||
import '../../components/ui/Tabler.css';
|
import '../../components/ui/Tabler.css';
|
||||||
|
import { LoginState } from '../../initialState';
|
||||||
|
|
||||||
type LoginProps = {
|
export const Login = () => {
|
||||||
login: {
|
const dispatch = useDispatch();
|
||||||
processingLogin: boolean;
|
const { processingLogin } = useSelector((state: LoginState) => state.login);
|
||||||
};
|
const [isForgotPasswordVisible, setIsForgotPasswordVisible] = useState(false);
|
||||||
processLogin: (args: { name: string; password: string }) => unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
type LoginState = {
|
const handleSubmit = ({ username: name, password }: LoginFormValues) => {
|
||||||
isForgotPasswordVisible: boolean;
|
dispatch(actionCreators.processLogin({ name, password }));
|
||||||
};
|
|
||||||
|
|
||||||
class Login extends Component<LoginProps, LoginState> {
|
|
||||||
state = {
|
|
||||||
isForgotPasswordVisible: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
handleSubmit = ({ username: name, password }: { username: string; password: string }) => {
|
const toggleText = () => {
|
||||||
this.props.processLogin({ name, password });
|
setIsForgotPasswordVisible((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleText = () => {
|
return (
|
||||||
this.setState((prevState) => ({
|
<div className="login">
|
||||||
isForgotPasswordVisible: !prevState.isForgotPasswordVisible,
|
<div className="login__form">
|
||||||
}));
|
<div className="text-center mb-6">
|
||||||
};
|
<Logo className="h-6 login__logo" />
|
||||||
|
|
||||||
render() {
|
|
||||||
const { processingLogin } = this.props.login;
|
|
||||||
const { isForgotPasswordVisible } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="login">
|
|
||||||
<div className="login__form">
|
|
||||||
<div className="text-center mb-6">
|
|
||||||
<Logo className="h-6 login__logo" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Form onSubmit={this.handleSubmit} processing={processingLogin} />
|
|
||||||
|
|
||||||
<div className="login__info">
|
|
||||||
<button type="button" className="btn btn-link login__link" onClick={this.toggleText}>
|
|
||||||
<Trans>forgot_password</Trans>
|
|
||||||
</button>
|
|
||||||
{isForgotPasswordVisible && (
|
|
||||||
<div className="login__message">
|
|
||||||
<Trans
|
|
||||||
components={[
|
|
||||||
<a
|
|
||||||
href="https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#password-reset"
|
|
||||||
key="0"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer">
|
|
||||||
link
|
|
||||||
</a>,
|
|
||||||
]}>
|
|
||||||
forgot_password_desc
|
|
||||||
</Trans>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Footer />
|
<Form onSubmit={handleSubmit} processing={processingLogin} />
|
||||||
|
|
||||||
<Toasts />
|
<div className="login__info">
|
||||||
|
<button type="button" className="btn btn-link login__link" onClick={toggleText}>
|
||||||
|
<Trans>forgot_password</Trans>
|
||||||
|
</button>
|
||||||
|
|
||||||
<Icons />
|
{isForgotPasswordVisible && (
|
||||||
|
<div className="login__message">
|
||||||
|
<Trans
|
||||||
|
components={[
|
||||||
|
<a
|
||||||
|
href="https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#password-reset"
|
||||||
|
key="0"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer">
|
||||||
|
link
|
||||||
|
</a>,
|
||||||
|
]}>
|
||||||
|
forgot_password_desc
|
||||||
|
</Trans>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = ({ login, toasts }: any) => ({ login, toasts });
|
<Footer />
|
||||||
|
<Toasts />
|
||||||
export default flow([withTranslation(), connect(mapStateToProps, actionCreators)])(Login);
|
<Icons />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import configureStore from '../configureStore';
|
|||||||
import reducers from '../reducers/login';
|
import reducers from '../reducers/login';
|
||||||
import '../i18n';
|
import '../i18n';
|
||||||
|
|
||||||
import Login from './Login';
|
import { Login } from './Login';
|
||||||
import { LoginState } from '../initialState';
|
import { LoginState } from '../initialState';
|
||||||
|
|
||||||
const store = configureStore<LoginState>(reducers, {});
|
const store = configureStore<LoginState>(reducers, {});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { test, expect } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
|
|
||||||
const ADMIN_USERNAME = 'admin';
|
const ADMIN_USERNAME = 'admin';
|
||||||
const ADMIN_PASSWORD = 'superpassword';
|
const ADMIN_PASSWORD = 'superpassword';
|
||||||
@@ -6,12 +6,13 @@ const PORT = 3000;
|
|||||||
|
|
||||||
test('install', async ({ page }) => {
|
test('install', async ({ page }) => {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
await page.getByRole('button', { name: 'Get Started' }).click();
|
await page.getByTestId('install_get_started').click();
|
||||||
await page.locator('input[name="web\\.port"]').fill(PORT.toString());
|
await page.getByTestId('install_web_port').fill(PORT.toString());
|
||||||
await page.getByRole('button', { name: 'Next' }).click();
|
await page.getByTestId('install_next').click();
|
||||||
await page.getByPlaceholder('Enter username').fill(ADMIN_USERNAME);
|
await page.getByTestId('install_username').fill(ADMIN_USERNAME);
|
||||||
await page.getByPlaceholder('Enter password').fill(ADMIN_PASSWORD);
|
await page.getByTestId('install_password').fill(ADMIN_PASSWORD);
|
||||||
await page.getByPlaceholder('Confirm password').fill(ADMIN_PASSWORD);
|
await page.getByTestId('install_confirm_password').fill(ADMIN_PASSWORD);
|
||||||
await page.getByRole('button', { name: 'Next' }).click();
|
await page.getByTestId('install_next').click();
|
||||||
await page.getByRole('button', { name: 'Next' }).click();
|
await page.getByTestId('install_next').click();
|
||||||
|
await page.getByTestId('install_open_dashboard').click();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user