From 92ba1ab8454a6b688db75490f613e8b3a651bc9a Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Wed, 9 Nov 2022 13:52:39 +0300 Subject: [PATCH] New authentication UI (#5181) * Add social accounts authentication && improve email confirmation * Pass env variables to docker * Update helm chart * Update email verification templates * Small refactoring * Send email verification && redirect to /auth/email-verification-sent * added new login form * added main assets * added main social buttons * changed reset password form * refactored reset password page * Fix helm chart * Fix typo * Pass enabled advanced auth methods to client * Rename class * Fix * Fix helm * Fix github scope * changed register page * adjusted no social auth methods * Some fixes * Fix schema generation * Fixes * Apply comments * Update changelog * added responsiveness, refactored inputs * cleanup * fixed email-confirmed.tsx * updated reset page, changed style on register page * added fonts, fixed some ui problems * removed some code * fixed index.html * made resizing less expressed * fixed form sizing, issue#5166 * fixed submiting form by enter * made toggle bigger, fixed headers * updated versions * removed extra lines * fixed fields on form * changed tests * fixed more tests * fixed comments * reverted header * added grid-unit-size for height, removed for fonts * added new animation Co-authored-by: Maya --- CHANGELOG.md | 2 +- cvat-core/package.json | 2 +- cvat-core/src/api-implementation.ts | 6 +- cvat-core/src/api.ts | 12 +- cvat-core/src/server-proxy.ts | 6 +- cvat-ui/package.json | 2 +- cvat-ui/src/actions/auth-actions.ts | 6 +- cvat-ui/src/assets/back-arrow-icon.svg | 3 + cvat-ui/src/assets/clear-icon.svg | 5 + cvat-ui/src/assets/cvat-minimalistic-logo.svg | 6 + cvat-ui/src/assets/index.d.ts | 5 + cvat-ui/src/assets/show-password.svg | 5 + cvat-ui/src/assets/signing-background.svg | 11 + cvat-ui/src/assets/social-github-logo.svg | 3 + cvat-ui/src/assets/social-google-logo.svg | 7 + .../email-confirmed.tsx | 7 +- .../src/components/login-page/login-form.tsx | 183 +++++++--- .../src/components/login-page/login-page.tsx | 108 ++---- .../register-page/register-form.tsx | 333 ++++++++--------- .../register-page/register-page.tsx | 41 +-- .../src/components/register-page/styles.scss | 7 - .../reset-password-form.tsx | 112 ++++-- .../reset-password-page.tsx | 69 +--- .../signing-common/cvat-signing-input.tsx | 52 +++ .../signing-common/signing-layout.tsx | 83 +++++ .../signing-common/social-account-link.tsx | 43 +++ .../src/components/signing-common/styles.scss | 338 ++++++++++++++++++ .../register-page/register-page.tsx | 3 +- cvat-ui/src/icons.tsx | 12 + cvat-ui/src/index.html | 4 +- cvat-ui/src/utils/validation-patterns.ts | 4 +- cvat-ui/tsconfig.json | 2 +- .../case_73_reset_password_notification.js | 2 +- .../actions_users/issue_1810_login_logout.js | 4 +- .../issue_1599_ch_user_registration.js | 14 +- .../issue_1599_pl_user_registration.js | 14 +- tests/cypress/support/commands.js | 13 +- yarn.lock | 2 +- 38 files changed, 1056 insertions(+), 475 deletions(-) create mode 100644 cvat-ui/src/assets/back-arrow-icon.svg create mode 100644 cvat-ui/src/assets/clear-icon.svg create mode 100644 cvat-ui/src/assets/cvat-minimalistic-logo.svg create mode 100644 cvat-ui/src/assets/index.d.ts create mode 100644 cvat-ui/src/assets/show-password.svg create mode 100644 cvat-ui/src/assets/signing-background.svg create mode 100644 cvat-ui/src/assets/social-github-logo.svg create mode 100644 cvat-ui/src/assets/social-google-logo.svg delete mode 100644 cvat-ui/src/components/register-page/styles.scss create mode 100644 cvat-ui/src/components/signing-common/cvat-signing-input.tsx create mode 100644 cvat-ui/src/components/signing-common/signing-layout.tsx create mode 100644 cvat-ui/src/components/signing-common/social-account-link.tsx create mode 100644 cvat-ui/src/components/signing-common/styles.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index c00aa3f9..1ebdc34e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Mask tools are supported now (brush, eraser, polygon-plus, polygon-minus, returning masks from online detectors & interactors) () - Added Webhooks () -- Authentication with social accounts google & github () +- Authentication with social accounts google & github (, ) - REST API tests to export job datasets & annotations and validate their structure () ### Changed diff --git a/cvat-core/package.json b/cvat-core/package.json index 0e0b7ee4..182edf8b 100644 --- a/cvat-core/package.json +++ b/cvat-core/package.json @@ -1,6 +1,6 @@ { "name": "cvat-core", - "version": "7.1.0", + "version": "7.2.0", "description": "Part of Computer Vision Tool which presents an interface for client-side integration", "main": "src/api.ts", "scripts": { diff --git a/cvat-core/src/api-implementation.ts b/cvat-core/src/api-implementation.ts index 2fa44cc8..2e18e653 100644 --- a/cvat-core/src/api-implementation.ts +++ b/cvat-core/src/api-implementation.ts @@ -63,8 +63,7 @@ const config = require('./config').default; firstName, lastName, email, - password1, - password2, + password, userConfirmations, ) => { const user = await serverProxy.server.register( @@ -72,8 +71,7 @@ const config = require('./config').default; firstName, lastName, email, - password1, - password2, + password, userConfirmations, ); diff --git a/cvat-core/src/api.ts b/cvat-core/src/api.ts index 97a9dd90..a12d0371 100644 --- a/cvat-core/src/api.ts +++ b/cvat-core/src/api.ts @@ -127,22 +127,20 @@ function build() { * @param {string} firstName A first name for the new account * @param {string} lastName A last name for the new account * @param {string} email A email address for the new account - * @param {string} password1 A password for the new account - * @param {string} password2 The confirmation password for the new account + * @param {string} password A password for the new account * @param {Object} userConfirmations An user confirmations of terms of use if needed * @returns {Object} response data * @throws {module:API.cvat.exceptions.PluginError} * @throws {module:API.cvat.exceptions.ServerError} */ - async register(username, firstName, lastName, email, password1, password2, userConfirmations) { + async register(username, firstName, lastName, email, password, userConfirmations) { const result = await PluginRegistry.apiWrapper( cvat.server.register, username, firstName, lastName, email, - password1, - password2, + password, userConfirmations, ); return result; @@ -173,6 +171,10 @@ function build() { const result = await PluginRegistry.apiWrapper(cvat.server.logout); return result; }, + async advancedAuthentication() { + const result = await PluginRegistry.apiWrapper(cvat.server.advancedAuthentication); + return result; + }, /** * Method returns enabled advanced authentication methods * @method advancedAuthentication diff --git a/cvat-core/src/server-proxy.ts b/cvat-core/src/server-proxy.ts index 0cabe755..9eaf63df 100644 --- a/cvat-core/src/server-proxy.ts +++ b/cvat-core/src/server-proxy.ts @@ -313,7 +313,7 @@ class ServerProxy { } } - async function register(username, firstName, lastName, email, password1, password2, confirmations) { + async function register(username, firstName, lastName, email, password, confirmations) { let response = null; try { const data = JSON.stringify({ @@ -321,8 +321,8 @@ class ServerProxy { first_name: firstName, last_name: lastName, email, - password1, - password2, + password1: password, + password2: password, confirmations, }); response = await Axios.post(`${config.backendAPI}/auth/register`, data, { diff --git a/cvat-ui/package.json b/cvat-ui/package.json index 5bb69506..28c49725 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.43.0", + "version": "1.43.1", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": { diff --git a/cvat-ui/src/actions/auth-actions.ts b/cvat-ui/src/actions/auth-actions.ts index aafce8dd..589792c7 100644 --- a/cvat-ui/src/actions/auth-actions.ts +++ b/cvat-ui/src/actions/auth-actions.ts @@ -91,8 +91,7 @@ export const registerAsync = ( firstName: string, lastName: string, email: string, - password1: string, - password2: string, + password: string, confirmations: UserConfirmation[], ): ThunkAction => async (dispatch) => { dispatch(authActions.register()); @@ -103,8 +102,7 @@ export const registerAsync = ( firstName, lastName, email, - password1, - password2, + password, confirmations, ); diff --git a/cvat-ui/src/assets/back-arrow-icon.svg b/cvat-ui/src/assets/back-arrow-icon.svg new file mode 100644 index 00000000..203318e4 --- /dev/null +++ b/cvat-ui/src/assets/back-arrow-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/cvat-ui/src/assets/clear-icon.svg b/cvat-ui/src/assets/clear-icon.svg new file mode 100644 index 00000000..bae640d7 --- /dev/null +++ b/cvat-ui/src/assets/clear-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/cvat-ui/src/assets/cvat-minimalistic-logo.svg b/cvat-ui/src/assets/cvat-minimalistic-logo.svg new file mode 100644 index 00000000..c8a10ba9 --- /dev/null +++ b/cvat-ui/src/assets/cvat-minimalistic-logo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/cvat-ui/src/assets/index.d.ts b/cvat-ui/src/assets/index.d.ts new file mode 100644 index 00000000..82255972 --- /dev/null +++ b/cvat-ui/src/assets/index.d.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2022 CVAT.ai Corporation +// +// SPDX-License-Identifier: MIT + +declare module '*.svg'; diff --git a/cvat-ui/src/assets/show-password.svg b/cvat-ui/src/assets/show-password.svg new file mode 100644 index 00000000..5830b25e --- /dev/null +++ b/cvat-ui/src/assets/show-password.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/cvat-ui/src/assets/signing-background.svg b/cvat-ui/src/assets/signing-background.svg new file mode 100644 index 00000000..773fde50 --- /dev/null +++ b/cvat-ui/src/assets/signing-background.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/cvat-ui/src/assets/social-github-logo.svg b/cvat-ui/src/assets/social-github-logo.svg new file mode 100644 index 00000000..07199e72 --- /dev/null +++ b/cvat-ui/src/assets/social-github-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/cvat-ui/src/assets/social-google-logo.svg b/cvat-ui/src/assets/social-google-logo.svg new file mode 100644 index 00000000..c2a4eaa6 --- /dev/null +++ b/cvat-ui/src/assets/social-google-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/cvat-ui/src/components/email-confirmation-pages/email-confirmed.tsx b/cvat-ui/src/components/email-confirmation-pages/email-confirmed.tsx index 9ebc8c22..8103c670 100644 --- a/cvat-ui/src/components/email-confirmation-pages/email-confirmed.tsx +++ b/cvat-ui/src/components/email-confirmation-pages/email-confirmed.tsx @@ -1,4 +1,5 @@ // Copyright (C) 2021-2022 Intel Corporation +// Copyright (C) 2022 CVAT.ai Corporation // // SPDX-License-Identifier: MIT @@ -17,9 +18,9 @@ const { Countdown } = Statistic; */ function EmailConfirmationPage(): JSX.Element { - const linkRef = useRef(); - const onFinish = () => { - linkRef.current.click(); + const linkRef = useRef(null); + const onFinish = (): void => { + linkRef.current?.click(); }; return ( diff --git a/cvat-ui/src/components/login-page/login-form.tsx b/cvat-ui/src/components/login-page/login-form.tsx index fb7e622e..7a05fae5 100644 --- a/cvat-ui/src/components/login-page/login-form.tsx +++ b/cvat-ui/src/components/login-page/login-form.tsx @@ -3,11 +3,18 @@ // // SPDX-License-Identifier: MIT -import React from 'react'; +import React, { useCallback, useState } from 'react'; import Form from 'antd/lib/form'; import Button from 'antd/lib/button'; import Input from 'antd/lib/input'; -import { UserOutlined, LockOutlined } from '@ant-design/icons'; +import Icon from '@ant-design/icons'; +import { + BackArrowIcon, ClearIcon, +} from 'icons'; +import { Col, Row } from 'antd/lib/grid'; +import Title from 'antd/lib/typography/Title'; +import Text from 'antd/lib/typography/Text'; +import { Link } from 'react-router-dom'; export interface LoginData { credential: string; @@ -15,61 +22,139 @@ export interface LoginData { } interface Props { + renderResetPassword: boolean; fetching: boolean; + socialAuthentication: JSX.Element | null; onSubmit(loginData: LoginData): void; } function LoginFormComponent(props: Props): JSX.Element { - const { fetching, onSubmit } = props; - return ( -
- - } - placeholder='Email or Username' - /> - + const { + fetching, onSubmit, renderResetPassword, socialAuthentication, + } = props; + const [form] = Form.useForm(); + const [credential, setCredential] = useState(''); - { + form.setFieldsValue({ [name]: '' }); + }, [form]); + const forgotPasswordLink = ( + + + + Forgot password? + + + + ); + return ( +
+ + { + credential && ( + + { + setCredential(''); + form.setFieldsValue({ credential: '' }); + }} + /> + + ) + } + { + !credential && ( + + + + New user?  + Create an account + + + + ) + } + { + renderResetPassword && forgotPasswordLink + } + + + Sign in + + { + onSubmit(loginData); + }} > - } - placeholder='Password' - type='password' - /> - - - - - - + Email or username} + suffix={( + credential && ( + { + setCredential(''); + inputReset('credential'); + }} + /> + ) + )} + onChange={(event) => { + const { value } = event.target; + setCredential(value); + if (!value) inputReset('credential'); + }} + /> + + { + credential && ( + + Password + } + /> + + ) + } + { + credential || !socialAuthentication ? ( + + + + ) : socialAuthentication + } + +
); } diff --git a/cvat-ui/src/components/login-page/login-page.tsx b/cvat-ui/src/components/login-page/login-page.tsx index ee15d455..c0b35938 100644 --- a/cvat-ui/src/components/login-page/login-page.tsx +++ b/cvat-ui/src/components/login-page/login-page.tsx @@ -5,15 +5,12 @@ import React, { useEffect } from 'react'; import { RouteComponentProps, useHistory } from 'react-router'; -import { Link, withRouter } from 'react-router-dom'; -import Button from 'antd/lib/button'; -import Title from 'antd/lib/typography/Title'; -import Text from 'antd/lib/typography/Text'; +import { withRouter } from 'react-router-dom'; import { Row, Col } from 'antd/lib/grid'; -import Layout from 'antd/lib/layout'; -import Space from 'antd/lib/space'; -import { GithubOutlined, GooglePlusOutlined } from '@ant-design/icons'; +import SigningLayout, { formSizes } from 'components/signing-common/signing-layout'; +import SocialAccountLink from 'components/signing-common/social-account-link'; +import { SocialGithubLogo, SocialGoogleLogo } from 'icons'; import LoginForm, { LoginData } from './login-form'; import { getCore } from '../../cvat-core-wrapper'; @@ -32,14 +29,6 @@ interface LoginPageComponentProps { function LoginPageComponent(props: LoginPageComponentProps & RouteComponentProps): JSX.Element { const history = useHistory(); const { backendAPI } = cvat.config; - const sizes = { - style: { - width: 400, - }, - }; - - const { Content } = Layout; - const { fetching, renderResetPassword, hasEmailVerificationBeenSent, googleAuthentication, githubAuthentication, onLogin, loadAdvancedAuthenticationMethods, @@ -54,74 +43,43 @@ function LoginPageComponent(props: LoginPageComponentProps & RouteComponentProps }, []); return ( - - - - - - Login + + + + + {githubAuthentication && ( + + Continue with GitHub + + )} + {googleAuthentication && ( + + Continue with Google + + )} + + ) : null} onSubmit={(loginData: LoginData): void => { onLogin(loginData.credential, loginData.password); }} /> - {(googleAuthentication || githubAuthentication) && - ( - <> - - - or - - - - {googleAuthentication && ( - - - - )} - {githubAuthentication && ( - - - - )} - - - )} - - - - New to CVAT? Create - an account - - - - {renderResetPassword && ( - - - - Forgot your password? - - - - )} - - + + ); } diff --git a/cvat-ui/src/components/register-page/register-form.tsx b/cvat-ui/src/components/register-page/register-form.tsx index c1972b5b..fedcaa28 100644 --- a/cvat-ui/src/components/register-page/register-form.tsx +++ b/cvat-ui/src/components/register-page/register-form.tsx @@ -3,17 +3,21 @@ // // SPDX-License-Identifier: MIT -import React, { useState } from 'react'; -import { UserAddOutlined, MailOutlined, LockOutlined } from '@ant-design/icons'; +import React, { useCallback, useState } from 'react'; +import Icon from '@ant-design/icons'; import Form, { RuleRender, RuleObject } from 'antd/lib/form'; import Button from 'antd/lib/button'; import Input from 'antd/lib/input'; +import Text from 'antd/lib/typography/Text'; import Checkbox from 'antd/lib/checkbox'; +import { Link } from 'react-router-dom'; +import { BackArrowIcon } from 'icons'; import patterns from 'utils/validation-patterns'; import { UserAgreement } from 'reducers'; import { Row, Col } from 'antd/lib/grid'; +import CVATSigningInput from 'components/signing-common/cvat-signing-input'; export interface UserConfirmation { name: string; @@ -25,8 +29,7 @@ export interface RegisterData { firstName: string; lastName: string; email: string; - password1: string; - password2: string; + password: string; confirmations: UserConfirmation[]; } @@ -98,182 +101,182 @@ const validateAgreement: ((userAgreements: UserAgreement[]) => RuleRender) = ( }); function RegisterFormComponent(props: Props): JSX.Element { - const { fetching, userAgreements, onSubmit } = props; + const { fetching, onSubmit, userAgreements } = props; const [form] = Form.useForm(); const [usernameEdited, setUsernameEdited] = useState(false); + const inputReset = useCallback((name: string):void => { + form.setFieldsValue({ [name]: '' }); + }, [form]); return ( -
) => { - const agreements = Object.keys(values) - .filter((key: string):boolean => key.startsWith('agreement:')); - const confirmations = agreements - .map((key: string): UserConfirmation => ({ name: key.split(':')[1], value: (values[key] as boolean) })); - const rest = Object.entries(values) - .filter((entry: (string | boolean)[]) => !agreements.includes(entry[0] as string)); - - onSubmit({ - ...(Object.fromEntries(rest) as any as RegisterData), - confirmations, - }); - }} - className='register-form' - > - - - - } - placeholder='First name' - /> - - - - - } - placeholder='Last name' - /> - +
+ + + - - } - placeholder='Email address' - onChange={(event) => { - const { value } = event.target; - if (!usernameEdited) { - const [username] = value.split('@'); - form.setFieldsValue({ username }); - } - }} - /> - - - } - placeholder='Username' - onChange={() => setUsernameEdited(true)} - /> - - - } - placeholder='Password' - /> - + ) => { + const agreements = Object.keys(values) + .filter((key: string):boolean => key.startsWith('agreement:')); + const confirmations = agreements + .map((key: string): UserConfirmation => ({ name: key.split(':')[1], value: (values[key] as boolean) })); + const rest = Object.entries(values) + .filter((entry: (string | boolean)[]) => !agreements.includes(entry[0] as string)); - - } - placeholder='Confirm password' - /> - - - {userAgreements.map((userAgreement: UserAgreement): JSX.Element => ( + + + + inputReset('firstName')} + /> + + + + + inputReset('lastName')} + /> + + + - - {userAgreement.textPrefix} - {!!userAgreement.url && - - {` ${userAgreement.urlDisplayText}`} - - } - + inputReset('email')} + onChange={(event) => { + const { value } = event.target; + if (!usernameEdited) { + const [username] = value.split('@'); + form.setFieldsValue({ username }); + } + }} + /> - ))} - - - - - + Password} + /> + + + {userAgreements.map((userAgreement: UserAgreement): JSX.Element => ( + + + {userAgreement.textPrefix} + {!!userAgreement.url && ( + + {` ${userAgreement.urlDisplayText}`} + + )} + + + ))} + + + + + +
); } diff --git a/cvat-ui/src/components/register-page/register-page.tsx b/cvat-ui/src/components/register-page/register-page.tsx index de6171c1..32f9eb78 100644 --- a/cvat-ui/src/components/register-page/register-page.tsx +++ b/cvat-ui/src/components/register-page/register-page.tsx @@ -3,16 +3,13 @@ // // SPDX-License-Identifier: MIT -import './styles.scss'; import React from 'react'; import { RouteComponentProps } from 'react-router'; -import { Link, withRouter } from 'react-router-dom'; -import Title from 'antd/lib/typography/Title'; -import Text from 'antd/lib/typography/Text'; +import { withRouter } from 'react-router-dom'; import { Row, Col } from 'antd/lib/grid'; -import Layout from 'antd/lib/layout'; import { UserAgreement } from 'reducers'; +import SigningLayout, { formSizes } from 'components/signing-common/signing-layout'; import RegisterForm, { RegisterData, UserConfirmation } from './register-form'; interface RegisterPageComponentProps { @@ -23,28 +20,19 @@ interface RegisterPageComponentProps { firstName: string, lastName: string, email: string, - password1: string, - password2: string, + password: string, confirmations: UserConfirmation[], ) => void; } function RegisterPageComponent(props: RegisterPageComponentProps & RouteComponentProps): JSX.Element { - const sizes = { - style: { - width: 400, - }, - }; - const { fetching, userAgreements, onRegister } = props; - const { Content } = Layout; return ( - - - - - Create an account + + + + - - - - Already have an account? - Login - - - - - + + ); } diff --git a/cvat-ui/src/components/register-page/styles.scss b/cvat-ui/src/components/register-page/styles.scss deleted file mode 100644 index ebc8c2c3..00000000 --- a/cvat-ui/src/components/register-page/styles.scss +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (C) 2020-2022 Intel Corporation -// -// SPDX-License-Identifier: MIT - -.ant-form-item { - margin-bottom: 12px; -} diff --git a/cvat-ui/src/components/reset-password-page/reset-password-form.tsx b/cvat-ui/src/components/reset-password-page/reset-password-form.tsx index bd12eb5e..9b014dd8 100644 --- a/cvat-ui/src/components/reset-password-page/reset-password-form.tsx +++ b/cvat-ui/src/components/reset-password-page/reset-password-form.tsx @@ -1,12 +1,18 @@ // Copyright (C) 2020-2022 Intel Corporation +// Copyright (C) 2022 CVAT.ai Corp // // SPDX-License-Identifier: MIT -import React from 'react'; +import React, { useCallback } from 'react'; import Form from 'antd/lib/form'; import Button from 'antd/lib/button'; -import { MailOutlined } from '@ant-design/icons'; -import Input from 'antd/lib/input'; +import Icon from '@ant-design/icons'; +import Text from 'antd/lib/typography/Text'; +import { BackArrowIcon } from 'icons'; +import { Col, Row } from 'antd/lib/grid'; +import { Link, useLocation } from 'react-router-dom'; +import Title from 'antd/lib/typography/Title'; +import CVATSigningInput from 'components/signing-common/cvat-signing-input'; export interface ResetPasswordData { email: string; @@ -18,41 +24,77 @@ interface Props { } function ResetPasswordFormComponent({ fetching, onSubmit }: Props): JSX.Element { + const [form] = Form.useForm(); + const location = useLocation(); + const params = new URLSearchParams(location.search); + const defaultCredential = params.get('credential'); + const inputReset = useCallback((name: string):void => { + form.setFieldsValue({ [name]: '' }); + }, [form]); return ( -
- - } - placeholder='Email address' +
+ + } /> - - - - - - + inputReset('email')} + /> + + + + We will send link to your email + + + + + + +
); } diff --git a/cvat-ui/src/components/reset-password-page/reset-password-page.tsx b/cvat-ui/src/components/reset-password-page/reset-password-page.tsx index 8c59ed74..49aefe9b 100644 --- a/cvat-ui/src/components/reset-password-page/reset-password-page.tsx +++ b/cvat-ui/src/components/reset-password-page/reset-password-page.tsx @@ -4,77 +4,34 @@ // SPDX-License-Identifier: MIT import React from 'react'; -import { Link } from 'react-router-dom'; -import { connect } from 'react-redux'; -import Title from 'antd/lib/typography/Title'; -import Text from 'antd/lib/typography/Text'; +import { useDispatch, useSelector } from 'react-redux'; import { Row, Col } from 'antd/lib/grid'; -import Layout from 'antd/lib/layout'; import { requestPasswordResetAsync } from 'actions/auth-actions'; import { CombinedState } from 'reducers'; +import SigningLayout, { formSizes } from 'components/signing-common/signing-layout'; import ResetPasswordForm, { ResetPasswordData } from './reset-password-form'; -interface StateToProps { - fetching: boolean; -} - -interface DispatchToProps { - onResetPassword: typeof requestPasswordResetAsync; -} - -interface ResetPasswordPageComponentProps { - fetching: boolean; - onResetPassword: (email: string) => void; -} - -function mapStateToProps(state: CombinedState): StateToProps { - return { - fetching: state.auth.fetching, - }; -} - -const mapDispatchToProps: DispatchToProps = { - onResetPassword: requestPasswordResetAsync, -}; - -function ResetPasswordPagePageComponent(props: ResetPasswordPageComponentProps): JSX.Element { - const sizes = { - xs: { span: 14 }, - sm: { span: 14 }, - md: { span: 10 }, - lg: { span: 4 }, - xl: { span: 4 }, - }; - - const { fetching, onResetPassword } = props; - const { Content } = Layout; +function ResetPasswordPagePageComponent(): JSX.Element { + const dispatch = useDispatch(); + const fetching = useSelector((state: CombinedState) => state.auth.fetching); return ( - - - - - Reset password + + + + { - onResetPassword(resetPasswordData.email); + dispatch(requestPasswordResetAsync(resetPasswordData.email)); }} /> - - - - Go to - login page - - - - - + + ); } -export default connect(mapStateToProps, mapDispatchToProps)(ResetPasswordPagePageComponent); +export default React.memo(ResetPasswordPagePageComponent); diff --git a/cvat-ui/src/components/signing-common/cvat-signing-input.tsx b/cvat-ui/src/components/signing-common/cvat-signing-input.tsx new file mode 100644 index 00000000..16623a79 --- /dev/null +++ b/cvat-ui/src/components/signing-common/cvat-signing-input.tsx @@ -0,0 +1,52 @@ +// Copyright (C) 2022 CVAT.ai Corporation +// +// SPDX-License-Identifier: MIT +import React, { useState } from 'react'; +import Icon from '@ant-design/icons'; +import Text from 'antd/lib/typography/Text'; +import { ClearIcon } from 'icons'; +import { Input } from 'antd'; + +interface SocialAccountLinkProps { + id?: string; + prefix: string; + autoComplete?: string; + placeholder: string; + value?: string; + onReset: () => void; + onChange?: (event: React.ChangeEvent) => void; +} + +function CVATSigningInput(props: SocialAccountLinkProps): JSX.Element { + const { + id, prefix, autoComplete, onReset, placeholder, value, onChange, + } = props; + const [valueNonEmpty, setValueNonEmpty] = useState(false); + return ( + {prefix}} + id={id} + suffix={( + valueNonEmpty ? ( + { + setValueNonEmpty(false); + onReset(); + }} + /> + ) : null + )} + onChange={(event: React.ChangeEvent) => { + const { value: inputValue } = event.target; + setValueNonEmpty(!!inputValue); + if (onChange) onChange(event); + }} + /> + ); +} + +export default React.memo(CVATSigningInput); diff --git a/cvat-ui/src/components/signing-common/signing-layout.tsx b/cvat-ui/src/components/signing-common/signing-layout.tsx new file mode 100644 index 00000000..7520a788 --- /dev/null +++ b/cvat-ui/src/components/signing-common/signing-layout.tsx @@ -0,0 +1,83 @@ +// Copyright (C) 2022 CVAT.ai Corporation +// +// SPDX-License-Identifier: MIT + +import './styles.scss'; +import React from 'react'; +import Layout from 'antd/lib/layout'; +import { Col, Row } from 'antd/lib/grid'; +import { CVATMinimalisticLogo } from 'icons'; +import Icon from '@ant-design/icons'; +import Title from 'antd/lib/typography/Title'; +import SVGSigningBackground from '../../assets/signing-background.svg'; + +interface SignInLayoutComponentProps { + children: JSX.Element | JSX.Element[]; +} + +interface Sizes { + xs?: { span: number }; + sm?: { span: number }; + md?: { span: number }; + lg?: { span: number }; + xl?: { span: number }; + xxl?: { span: number }; +} + +interface FormSizes { + wrapper: Sizes; + form: Sizes; +} + +export const formSizes: FormSizes = { + wrapper: { + xs: { span: 24 }, + sm: { span: 24 }, + md: { span: 24 }, + lg: { span: 24 }, + xl: { span: 15 }, + xxl: { span: 12 }, + }, + form: { + xs: { span: 14 }, + sm: { span: 14 }, + md: { span: 14 }, + lg: { span: 14 }, + xl: { span: 16 }, + xxl: { span: 16 }, + }, +}; + +function SignInLayout(props: SignInLayoutComponentProps): JSX.Element { + const { children } = props; + const { Content, Header } = Layout; + const titleSizes = { + xs: { span: 0 }, + sm: { span: 0 }, + md: { span: 0 }, + lg: { span: 0 }, + xl: { span: 8 }, + xxl: { span: 10 }, + }; + return ( + + +
+ +
+ + + + + Open Data + Annotation Platform + + {children} + + + +
+ ); +} + +export default SignInLayout; diff --git a/cvat-ui/src/components/signing-common/social-account-link.tsx b/cvat-ui/src/components/signing-common/social-account-link.tsx new file mode 100644 index 00000000..7cea010c --- /dev/null +++ b/cvat-ui/src/components/signing-common/social-account-link.tsx @@ -0,0 +1,43 @@ +// Copyright (C) 2022 CVAT.ai Corporation +// +// SPDX-License-Identifier: MIT +import './styles.scss'; +import React from 'react'; +import { Col, Row } from 'antd/lib/grid'; +import Button from 'antd/lib/button/button'; +import Icon from '@ant-design/icons'; +import { CustomIconComponentProps } from '@ant-design/icons/lib/components/Icon'; + +interface SocialAccountLinkProps { + children: string; + className?: string; + href: string; + icon: React.ForwardRefExoticComponent; +} + +function SocialAccountLink(props: SocialAccountLinkProps): JSX.Element { + const { + children, className, href, icon, + } = props; + return ( + + + + + + ); +} + +export default React.memo(SocialAccountLink); diff --git a/cvat-ui/src/components/signing-common/styles.scss b/cvat-ui/src/components/signing-common/styles.scss new file mode 100644 index 00000000..bf7240d3 --- /dev/null +++ b/cvat-ui/src/components/signing-common/styles.scss @@ -0,0 +1,338 @@ +// Copyright (C) 2022 CVAT.ai Corporation +// +// SPDX-License-Identifier: MIT +@import '../../styles.scss'; + +$heading-font: 'Sora', sans-serif; +$signing-font: 'Roboto Flex', sans-serif; + +$heading-color: white; +$error-color: #ff4d4f; +$action-button-color-1: black; +$action-button-color-2: gray; +$action-button-color-3: #d4d4d4; + +$base-transition: all 0.8s ease; + +$social-google-background: #4286f5; + +.cvat-signing-layout { + font-family: $signing-font; +} + +.cvat-signing-title { + .ant-typography { + color: $heading-color; + margin: 0; + font-size: 68px; + font-family: $heading-font; + font-weight: 400; + } + + .ant-typography:last-child { + margin: 0; + } +} + +.cvat-signing-header { + background: transparent; + position: absolute; +} + +.cvat-signing-background { + position: absolute; + width: 100%; + height: 100%; + min-width: $grid-unit-size*128; +} + +.cvat-credentials-link { + a { + color: black; + text-decoration: underline; + text-decoration-thickness: 2px; + } + + a:hover { + color: black; + text-decoration: underline; + text-decoration-thickness: 2px; + } +} + +.cvat-credentials-form-item { + .ant-input-affix-wrapper { + border: none; + box-shadow: 0 1px 0 0 $border-color-1; + border-radius: 0; + padding: 0; + transition: $base-transition; + } + + .ant-input-prefix { + position: absolute; + z-index: 1; + } + + .ant-input-affix-wrapper-focused { + box-shadow: 0 2px 0 0 black; + } + + .ant-input-affix-wrapper-focused:hover { + box-shadow: 0 2px 0 0 black; + } + + .ant-input { + font-size: 20px; + padding: $grid-unit-size * 1.5 0 $grid-unit-size * 0.75 0 !important; + + &:-webkit-autofill, + &:-webkit-autofill:hover, + &:-webkit-autofill:focus { + box-shadow: 0 0 0 1000px white inset !important; + transition: background-color 10s ease-in-out 0s; + } + } + + .ant-typography { + text-transform: uppercase; + color: $border-color-1; + font-size: 12px; + letter-spacing: 1px; + } +} + +.cvat-credentials-form-item.ant-form-item-has-error { + .ant-input-affix-wrapper { + border: none; + box-shadow: 0 1px 0 0 $error-color; + border-radius: 0; + padding: 0; + transition: $base-transition; + } + + .ant-input-affix-wrapper-focused { + box-shadow: 0 2px 0 0 $error-color !important; + } +} + +.cvat-credentials-navigation { + margin-bottom: $grid-unit-size*4; +} + +.cvat-credentials-action-button { + width: 100%; + border-radius: $grid-unit-size*2; + background-color: $action-button-color-1; + height: $grid-unit-size*11; + color: white; + font-size: 16px; + font-weight: bold; + border: none; + box-shadow: none; + transition: $base-transition; + + &:hover, + &:focus { + background-color: $action-button-color-1; + color: $action-button-color-2; + } +} + +.cvat-login-form-wrapper { + border-radius: $grid-unit-size * 4; + background: $background-color-1; + padding: $grid-unit-size * 6; + height: $grid-unit-size*81; + + .cvat-credentials-form-item { + height: $grid-unit-size*9.5; + + .ant-form-item-explain { + margin-bottom: $grid-unit-size*0.5; + } + } + + .ant-form-item { + margin-bottom: 0; + } + + .ant-form-item-explain-error:not(:first-child) { + display: none; + } +} + +.cvat-signing-form { + position: relative; + height: $grid-unit-size*52; + + .ant-form-item:last-child:not(.cvat-credentials-form-item) { + position: absolute; + bottom: $grid-unit-size*6; + width: 100%; + box-sizing: border-box; + } +} + +.cvat-login-form { + @extend .cvat-signing-form; + + margin-top: $grid-unit-size*10; + + .ant-form-item:first-child { + margin-bottom: $grid-unit-size*15; + } +} + +.cvat-login-form-extended { + .ant-form-item:first-child { + margin-bottom: 0; + } +} + +.cvat-password-reset-form-wrapper { + @extend .cvat-login-form-wrapper; + + h2 { + margin-bottom: 0; + } + + .cvat-password-reset-tip { + font-weight: bold; + margin-bottom: $grid-unit-size*20; + } +} + +.cvat-password-reset-form { + @extend .cvat-signing-form; + + .cvat-credentials-form-item { + margin-bottom: $grid-unit-size*3; + } + + margin-top: $grid-unit-size*6; +} + +.cvat-register-form-wrapper { + @extend .cvat-login-form-wrapper; + + .cvat-register-form { + @extend .cvat-signing-form; + + height: $grid-unit-size*68; + } + + .cvat-agreements-form-item { + height: $grid-unit-size*5.5; + + .ant-form-item-explain { + margin-top: -$grid-unit-size; + } + + .ant-checkbox-wrapper { + display: flex; + align-items: center; + } + + .ant-checkbox { + top: 0; + + .ant-checkbox-inner { + width: $grid-unit-size*5; + height: $grid-unit-size*3; + border-radius: 12px; + background: #d9d9d9; + border: none; + + &:hover { + border: none; + } + + &::after { + position: absolute; + content: ""; + height: $grid-unit-size*2; + width: $grid-unit-size*2; + border-radius: $grid-unit-size; + top: $grid-unit-size*0.5; + left: $grid-unit-size*0.5; + background-color: white; + opacity: 1; + transform: none; + border: none; + } + } + } + + .ant-checkbox-checked { + .ant-checkbox-inner { + width: $grid-unit-size*5; + height: $grid-unit-size*3; + border-radius: 12px; + background: $slider-color; + border: none; + + &:hover { + border: none; + } + + &::after { + position: absolute; + content: ""; + height: $grid-unit-size*2; + width: $grid-unit-size*2; + border-radius: $grid-unit-size; + top: $grid-unit-size*0.5; + left: $grid-unit-size*2.5; + background-color: white; + opacity: 1; + transform: none; + border: none; + } + } + } + } + + .cvat-register-form-last-field { + margin-bottom: 0; + } +} + +.cvat-register-form-wrapper-extended { + @extend .cvat-login-form-wrapper; + + height: $grid-unit-size*88; + + .cvat-register-form-last-field { + margin-bottom: $grid-unit-size; + } + + .cvat-register-form { + @extend .cvat-signing-form; + + height: $grid-unit-size*76; + } +} + +.cvat-social-authentication-button { + @extend .cvat-credentials-action-button; + + .anticon { + margin-top: $grid-unit-size*0.5; + } + + letter-spacing: 1px; + margin-bottom: $grid-unit-size; + padding: $grid-unit-size $grid-unit-size*4; + display: flex; +} + +.cvat-social-authentication-google { + background: $social-google-background; + + &:hover, + &:focus { + background: $social-google-background; + color: $action-button-color-3; + } +} diff --git a/cvat-ui/src/containers/register-page/register-page.tsx b/cvat-ui/src/containers/register-page/register-page.tsx index 408d2a2b..02d647c3 100644 --- a/cvat-ui/src/containers/register-page/register-page.tsx +++ b/cvat-ui/src/containers/register-page/register-page.tsx @@ -20,8 +20,7 @@ interface DispatchToProps { firstName: string, lastName: string, email: string, - password1: string, - password2: string, + password: string, userAgreement: UserConfirmation[], ) => void; } diff --git a/cvat-ui/src/icons.tsx b/cvat-ui/src/icons.tsx index 247f7213..e078b5a6 100644 --- a/cvat-ui/src/icons.tsx +++ b/cvat-ui/src/icons.tsx @@ -6,6 +6,7 @@ import React from 'react'; import SVGCVATLogo from './assets/cvat-logo.svg'; +import SVGCVATMinimalisticLogo from './assets/cvat-minimalistic-logo.svg'; import SVGCursorIcon from './assets/cursor-icon.svg'; import SVGMoveIcon from './assets/move-icon.svg'; import SVGRotateIcon from './assets/rotate-icon.svg'; @@ -58,10 +59,16 @@ import SVGEraserIcon from './assets/eraser-icon.svg'; import SVGPolygonPlusIcon from './assets/polygon-plus.svg'; import SVGPolygonMinusIcon from './assets/polygon-minus.svg'; import SVGMultiPlusIcon from './assets/multi-plus-icon.svg'; +import SVGBackArrowIcon from './assets/back-arrow-icon.svg'; +import SVGClearIcon from './assets/clear-icon.svg'; +import SVGShowPasswordIcon from './assets/show-password.svg'; +import SVGSocialGithubLogo from './assets/social-github-logo.svg'; +import SVGSocialGoogleLogo from './assets/social-google-logo.svg'; import SVGPlusIcon from './assets/plus-icon.svg'; import SVGCheckIcon from './assets/check-icon.svg'; export const CVATLogo = React.memo((): JSX.Element => ); +export const CVATMinimalisticLogo = React.memo((): JSX.Element => ); export const CursorIcon = React.memo((): JSX.Element => ); export const MoveIcon = React.memo((): JSX.Element => ); export const RotateIcon = React.memo((): JSX.Element => ); @@ -114,5 +121,10 @@ export const EraserIcon = React.memo((): JSX.Element => ); export const PolygonPlusIcon = React.memo((): JSX.Element => ); export const PolygonMinusIcon = React.memo((): JSX.Element => ); export const MutliPlusIcon = React.memo((): JSX.Element => ); +export const BackArrowIcon = React.memo((): JSX.Element => ); +export const ClearIcon = React.memo((): JSX.Element => ); +export const ShowPasswordIcon = React.memo((): JSX.Element => ); +export const SocialGithubLogo = React.memo((): JSX.Element => ); +export const SocialGoogleLogo = React.memo((): JSX.Element => ); export const PlusIcon = React.memo((): JSX.Element => ); export const CheckIcon = React.memo((): JSX.Element => ); diff --git a/cvat-ui/src/index.html b/cvat-ui/src/index.html index 9c514ba0..78d09624 100644 --- a/cvat-ui/src/index.html +++ b/cvat-ui/src/index.html @@ -15,9 +15,11 @@ content="Computer Vision Annotation Tool (CVAT) is a free, open source, web-based image and video annotation tool which is used for labeling data for computer vision algorithms. CVAT supports the primary tasks of supervised machine learning: object detection, image classification, and image segmentation. CVAT allows users to annotate data for each of these cases" /> + + + Computer Vision Annotation Tool -
diff --git a/cvat-ui/src/utils/validation-patterns.ts b/cvat-ui/src/utils/validation-patterns.ts index 9323b1f0..97e73654 100644 --- a/cvat-ui/src/utils/validation-patterns.ts +++ b/cvat-ui/src/utils/validation-patterns.ts @@ -29,8 +29,8 @@ const validationPatterns = { }, validateUsernameCharacters: { - pattern: /^[a-zA-Z0-9_-]{5,}$/, - message: 'Only characters (a-z), (A-Z), (0-9), -, _ are available', + pattern: /^[a-zA-Z0-9_\-.]{5,}$/, + message: 'Only characters (a-z), (A-Z), (0-9), -, _, . are available', }, /* diff --git a/cvat-ui/tsconfig.json b/cvat-ui/tsconfig.json index 9b0c02b6..2cb57ed4 100644 --- a/cvat-ui/tsconfig.json +++ b/cvat-ui/tsconfig.json @@ -16,5 +16,5 @@ "jsx": "preserve", "baseUrl": "src" }, - "include": ["./index.d.ts", "src/index.tsx", "src"] + "include": ["./index.d.ts", "src/index.tsx", "src/assets/index.d.ts", "src"] } diff --git a/tests/cypress/integration/actions_users/case_73_reset_password_notification.js b/tests/cypress/integration/actions_users/case_73_reset_password_notification.js index bd9eea28..484ad260 100644 --- a/tests/cypress/integration/actions_users/case_73_reset_password_notification.js +++ b/tests/cypress/integration/actions_users/case_73_reset_password_notification.js @@ -19,7 +19,7 @@ context('Reset password notification.', () => { it('Sending a password reset request', () => { cy.get('#email').type(dummyEmail); - cy.get('.cvat-reset-password-form-button').click(); + cy.get('.cvat-credentials-action-button').click(); cy.contains('Check your email').should('be.visible'); }); }); diff --git a/tests/cypress/integration/actions_users/issue_1810_login_logout.js b/tests/cypress/integration/actions_users/issue_1810_login_logout.js index 858c626c..476ce517 100644 --- a/tests/cypress/integration/actions_users/issue_1810_login_logout.js +++ b/tests/cypress/integration/actions_users/issue_1810_login_logout.js @@ -11,8 +11,8 @@ context('When clicking on the Logout button, get the user session closed.', () = let taskId; function login(credential, password) { - cy.get('[placeholder="Email or Username"]').clear().type(credential); - cy.get('[placeholder="Password"]').clear().type(password); + cy.get('[placeholder="enter your email or username"]').clear().type(credential); + cy.get('[placeholder="enter your password"]').clear().type(password); cy.get('[type="submit"]').click(); } diff --git a/tests/cypress/integration/actions_users/registration_involved/issue_1599_ch_user_registration.js b/tests/cypress/integration/actions_users/registration_involved/issue_1599_ch_user_registration.js index 4cf06d98..c9dfdbb7 100644 --- a/tests/cypress/integration/actions_users/registration_involved/issue_1599_ch_user_registration.js +++ b/tests/cypress/integration/actions_users/registration_involved/issue_1599_ch_user_registration.js @@ -25,27 +25,23 @@ context('Issue 1599 (Chinese alphabet).', () => { describe('User registration using the Chinese alphabet.', () => { it('Filling in the placeholder "First name"', () => { - cy.get('[placeholder="First name"]').type(firstName).should('not.have.class', 'has-error'); + cy.get('[placeholder="enter your first name"]').type(firstName).should('not.have.class', 'has-error'); }); it('Filling in the placeholder "Last name"', () => { - cy.get('[placeholder="Last name"]').type(lastName).should('not.have.class', 'has-error'); + cy.get('[placeholder="enter your last name"]').type(lastName).should('not.have.class', 'has-error'); }); it('Filling in the placeholder "Username"', () => { - cy.get('[placeholder="Username"]').type(userName); + cy.get('[placeholder="enter your username"]').type(userName); }); it('Filling in the placeholder "Email address"', () => { - cy.get('[placeholder="Email address"]').type(email); + cy.get('[placeholder="enter your email"]').type(email); }); it('Filling in the placeholder "Password"', () => { - cy.get('[placeholder="Password"]').type(password); - }); - - it('Filling in the placeholder "Confirm password"', () => { - cy.get('[placeholder="Confirm password"]').type(password); + cy.get('[placeholder="enter your password"]').type(password); }); it('Click to "Submit" button', () => { diff --git a/tests/cypress/integration/actions_users/registration_involved/issue_1599_pl_user_registration.js b/tests/cypress/integration/actions_users/registration_involved/issue_1599_pl_user_registration.js index 3abbdfb7..70e5a778 100644 --- a/tests/cypress/integration/actions_users/registration_involved/issue_1599_pl_user_registration.js +++ b/tests/cypress/integration/actions_users/registration_involved/issue_1599_pl_user_registration.js @@ -25,27 +25,23 @@ context('Issue 1599 (Polish alphabet).', () => { describe('User registration using the Polish alphabet.', () => { it('Filling in the placeholder "First name"', () => { - cy.get('[placeholder="First name"]').type(firstName).should('not.have.class', 'has-error'); + cy.get('[placeholder="enter your first name"]').type(firstName).should('not.have.class', 'has-error'); }); it('Filling in the placeholder "Last name"', () => { - cy.get('[placeholder="Last name"]').type(lastName).should('not.have.class', 'has-error'); + cy.get('[placeholder="enter your last name"]').type(lastName).should('not.have.class', 'has-error'); }); it('Filling in the placeholder "Username"', () => { - cy.get('[placeholder="Username"]').type(userName); + cy.get('[placeholder="enter your username"]').type(userName); }); it('Filling in the placeholder "Email address"', () => { - cy.get('[placeholder="Email address"]').type(email); + cy.get('[placeholder="enter your email"]').type(email); }); it('Filling in the placeholder "Password"', () => { - cy.get('[placeholder="Password"]').type(password); - }); - - it('Filling in the placeholder "Confirm password"', () => { - cy.get('[placeholder="Confirm password"]').type(password); + cy.get('[placeholder="enter your password"]').type(password); }); it('Click to "Submit" button', () => { diff --git a/tests/cypress/support/commands.js b/tests/cypress/support/commands.js index 95c6bfe3..e53016be 100644 --- a/tests/cypress/support/commands.js +++ b/tests/cypress/support/commands.js @@ -20,9 +20,9 @@ require('cy-verify-downloads').addCustomCommand(); let selectedValueGlobal = ''; Cypress.Commands.add('login', (username = Cypress.env('user'), password = Cypress.env('password'), page = 'tasks') => { - cy.get('[placeholder="Email or Username"]').type(username); - cy.get('[placeholder="Password"]').type(password); - cy.get('[type="submit"]').click(); + cy.get('[placeholder="enter your email or username"]').type(username); + cy.get('[placeholder="enter your password"]').type(password); + cy.get('.cvat-credentials-action-button').click(); cy.url().should('contain', `/${page}`); cy.document().then((doc) => { const loadSettingFailNotice = Array.from(doc.querySelectorAll('.cvat-notification-notice-load-settings-fail')); @@ -40,7 +40,7 @@ Cypress.Commands.add('logout', (username = Cypress.env('user')) => { cy.url().should('include', '/auth/login'); cy.visit('/auth/login'); cy.url().should('not.include', '?next='); - cy.contains('Login').should('exist'); + cy.contains('Sign in').should('exist'); }); Cypress.Commands.add('userRegistration', (firstName, lastName, userName, emailAddr, password) => { @@ -48,9 +48,8 @@ Cypress.Commands.add('userRegistration', (firstName, lastName, userName, emailAd cy.get('#lastName').type(lastName); cy.get('#username').type(userName); cy.get('#email').type(emailAddr); - cy.get('#password1').type(password); - cy.get('#password2').type(password); - cy.get('.register-form-button').click(); + cy.get('#password').type(password); + cy.get('.cvat-credentials-action-button').click(); if (Cypress.browser.family === 'chromium') { cy.url().should('include', '/tasks'); } diff --git a/yarn.lock b/yarn.lock index 151a1c4d..c6b59c6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4103,7 +4103,7 @@ custom-error-instance@2.1.1: svg.select.js "3.0.1" "cvat-core@link:./cvat-core": - version "7.0.1" + version "7.2.0" dependencies: axios "^0.27.2" browser-or-node "^2.0.0"