This commit is contained in:
Ildar Kamalov
2025-08-11 09:43:35 +03:00
parent f7357be494
commit d00f1e12b3
8 changed files with 69 additions and 43 deletions

View File

@@ -21,7 +21,7 @@ GO.MACRO = $${GO:-go}
VERBOSE.MACRO = $${VERBOSE:-0} VERBOSE.MACRO = $${VERBOSE:-0}
CHANNEL = development CHANNEL = development
CLIENT_DIR = client CLIENT_DIR = client_v2
DEPLOY_SCRIPT_PATH = not/a/real/path DEPLOY_SCRIPT_PATH = not/a/real/path
DIST_DIR = dist DIST_DIR = dist
GOAMD64 = v1 GOAMD64 = v1

View File

@@ -3,6 +3,7 @@ import React from 'react';
import { getIpList, getDnsAddress, getWebAddress } from '../../helpers/helpers'; import { getIpList, getDnsAddress, getWebAddress } from '../../helpers/helpers';
import { ALL_INTERFACES_IP } from '../../helpers/constants'; import { ALL_INTERFACES_IP } from '../../helpers/constants';
import { InstallInterface } from '../../initialState'; import { InstallInterface } from '../../initialState';
import theme from 'panel/lib/theme';
interface renderItemProps { interface renderItemProps {
ip: string; ip: string;
@@ -19,7 +20,7 @@ const renderItem = ({ ip, port, isDns }: renderItemProps) => {
{isDns ? ( {isDns ? (
<strong>{dnsAddress}</strong> <strong>{dnsAddress}</strong>
) : ( ) : (
<a href={webAddress} target="_blank" rel="noopener noreferrer"> <a href={webAddress} target="_blank" className={theme.link.link} rel="noopener noreferrer">
{webAddress} {webAddress}
</a> </a>
)} )}

View File

@@ -3,7 +3,7 @@ import { Controller, useForm } from 'react-hook-form';
import { Trans, useTranslation } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
import Controls from './Controls'; import Controls from './Controls';
import { validatePasswordLength, validateRequiredValue } from '../../helpers/validators'; import { validatePasswordLength, validateRequiredValue } from '../../helpers/validators';
import { Input } from '../../components/ui/Controls/Input'; import { Input } from 'panel/common/controls/Input';
type AuthFormValues = { type AuthFormValues = {
username: string; username: string;
@@ -60,10 +60,11 @@ export const Auth = ({ onAuthSubmit }: Props) => {
<Input <Input
{...field} {...field}
type="text" type="text"
id="install_username"
data-testid="install_username" data-testid="install_username"
label={t('install_auth_username')} label={t('install_auth_username')}
placeholder={t('install_auth_username_enter')} placeholder={t('install_auth_username_enter')}
error={fieldState.error?.message} errorMessage={fieldState.error?.message}
autoComplete="username" autoComplete="username"
/> />
)} )}
@@ -84,10 +85,11 @@ export const Auth = ({ onAuthSubmit }: Props) => {
<Input <Input
{...field} {...field}
type="password" type="password"
id="install_password"
data-testid="install_password" data-testid="install_password"
label={t('install_auth_password')} label={t('install_auth_password')}
placeholder={t('install_auth_password_enter')} placeholder={t('install_auth_password_enter')}
error={fieldState.error?.message} errorMessage={fieldState.error?.message}
autoComplete="new-password" autoComplete="new-password"
/> />
)} )}
@@ -108,10 +110,11 @@ export const Auth = ({ onAuthSubmit }: Props) => {
<Input <Input
{...field} {...field}
type="password" type="password"
id="install_confirm_password"
data-testid="install_confirm_password" data-testid="install_confirm_password"
label={t('install_auth_confirm')} label={t('install_auth_confirm')}
placeholder={t('install_auth_confirm')} placeholder={t('install_auth_confirm')}
error={fieldState.error?.message} errorMessage={fieldState.error?.message}
autoComplete="new-password" autoComplete="new-password"
/> />
)} )}

View File

@@ -3,6 +3,7 @@ import { connect } from 'react-redux';
import { Trans } from 'react-i18next'; import { Trans } from 'react-i18next';
import * as actionCreators from '../../actions/install'; import * as actionCreators from '../../actions/install';
import { Button } from 'panel/common/ui/Button';
interface ControlsProps { interface ControlsProps {
install: { install: {
@@ -33,13 +34,15 @@ class Controls extends Component<ControlsProps> {
case 2: case 2:
case 3: case 3:
return ( return (
<button <Button
data-testid="install_back" data-testid="install_back"
type="button" type="button"
className="btn btn-secondary btn-lg setup__button" size="small"
variant="secondary"
className="setup__button"
onClick={this.props.prevStep}> onClick={this.props.prevStep}>
<Trans>back</Trans> <Trans>back</Trans>
</button> </Button>
); );
default: default:
return false; return false;
@@ -52,44 +55,52 @@ class Controls extends Component<ControlsProps> {
switch (step) { switch (step) {
case 1: case 1:
return ( return (
<button <Button
data-testid="install_get_started" data-testid="install_get_started"
type="button" type="button"
className="btn btn-success btn-lg setup__button" onClick={nextStep}
onClick={nextStep}> size="small"
variant="primary"
className="setup__button">
<Trans>get_started</Trans> <Trans>get_started</Trans>
</button> </Button>
); );
case 2: case 2:
case 3: case 3:
return ( return (
<button <Button
data-testid="install_next" data-testid="install_next"
type="submit" type="submit"
className="btn btn-success btn-lg setup__button" size="small"
variant="primary"
className="setup__button"
disabled={invalid || pristine || install.processingSubmit}> disabled={invalid || pristine || install.processingSubmit}>
<Trans>next</Trans> <Trans>next</Trans>
</button> </Button>
); );
case 4: case 4:
return ( return (
<button <Button
data-testid="install_next" data-testid="install_next"
type="button" type="button"
className="btn btn-success btn-lg setup__button" size="small"
variant="primary"
className="setup__button"
onClick={nextStep}> onClick={nextStep}>
<Trans>next</Trans> <Trans>next</Trans>
</button> </Button>
); );
case 5: case 5:
return ( return (
<button <Button
data-testid="install_open_dashboard" data-testid="install_open_dashboard"
type="button" type="button"
className="btn btn-success btn-lg setup__button" size="small"
variant="primary"
className="setup__button"
onClick={() => this.props.openDashboard(ip, port)}> onClick={() => this.props.openDashboard(ip, port)}>
<Trans>open_dashboard</Trans> <Trans>open_dashboard</Trans>
</button> </Button>
); );
default: default:
return false; return false;
@@ -101,10 +112,8 @@ class Controls extends Component<ControlsProps> {
return ( return (
<div className="setup__nav"> <div className="setup__nav">
<div className="btn-list"> {this.renderPrevButton(install.step)}
{this.renderPrevButton(install.step)} {this.renderNextButton(install.step)}
{this.renderNextButton(install.step)}
</div>
</div> </div>
); );
} }

View File

@@ -52,7 +52,9 @@
} }
.setup__nav { .setup__nav {
text-align: center; display: flex;
gap: 16px;
justify-content: center;
} }
.setup__step { .setup__step {
@@ -130,9 +132,7 @@
} }
.setup__button { .setup__button {
min-width: 120px; max-width: 200px;
padding-left: 30px;
padding-right: 30px;
} }
.setup__error { .setup__error {

View File

@@ -1,8 +1,9 @@
import React from 'react'; import React from 'react';
import { Controller, useForm } from 'react-hook-form'; import { Controller, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Input } from '../../components/ui/Controls/Input'; import { validateRequiredValue } from 'panel/helpers/validators';
import { validateRequiredValue } from '../../helpers/validators'; import { Input } from 'panel/common/controls/Input';
import { Button } from 'panel/common/ui/Button';
export type LoginFormValues = { export type LoginFormValues = {
username: string; username: string;
@@ -39,14 +40,14 @@ const Form = ({ onSubmit, processing }: LoginFormProps) => {
render={({ field, fieldState }) => ( render={({ field, fieldState }) => (
<Input <Input
{...field} {...field}
id="username"
data-testid="username" data-testid="username"
type="text" type="text"
label={t('username_label')} label={t('username_label')}
placeholder={t('username_placeholder')} placeholder={t('username_placeholder')}
error={fieldState.error?.message} errorMessage={fieldState.error?.message}
autoComplete="username" autoComplete="username"
autoCapitalize="none" autoCapitalize="none"
disabled={processing}
/> />
)} )}
/> />
@@ -60,26 +61,28 @@ const Form = ({ onSubmit, processing }: LoginFormProps) => {
render={({ field, fieldState }) => ( render={({ field, fieldState }) => (
<Input <Input
{...field} {...field}
id="password"
data-testid="password" data-testid="password"
type="password" type="password"
label={t('password_label')} label={t('password_label')}
placeholder={t('password_placeholder')} placeholder={t('password_placeholder')}
error={fieldState.error?.message} errorMessage={fieldState.error?.message}
autoComplete="current-password" autoComplete="current-password"
disabled={processing}
/> />
)} )}
/> />
</div> </div>
<div className="form-footer"> <div className="form-footer">
<button <Button
id="sign_in"
data-testid="sign_in" data-testid="sign_in"
type="submit" type="submit"
className="btn btn-success btn-block" variant="primary"
size="small"
disabled={processing || !isValid}> disabled={processing || !isValid}>
{t('sign_in')} {t('sign_in')}
</button> </Button>
</div> </div>
</div> </div>
</form> </form>

View File

@@ -38,6 +38,12 @@
letter-spacing: 0; letter-spacing: 0;
} }
.login__link {
margin-top: 16px;
border: 0;
background: transparent;
}
@media screen and (min-width: 992px) { @media screen and (min-width: 992px) {
.login__message { .login__message {
position: absolute; position: absolute;

View File

@@ -1,14 +1,16 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { Trans } from 'react-i18next'; import { Trans } from 'react-i18next';
import cn from 'clsx';
import theme from 'panel/lib/theme';
import * as actionCreators from '../../actions/login'; import * as actionCreators from '../../actions/login';
import Toasts from '../../components/Toasts'; import Toasts from '../../components/Toasts';
import Form, { LoginFormValues } from './Form'; import Form, { LoginFormValues } from './Form';
import { LoginState } from '../../initialState';
import './Login.css'; import './Login.css';
import { LoginState } from '../../initialState';
export const Login = () => { export const Login = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -29,7 +31,7 @@ export const Login = () => {
<Form onSubmit={handleSubmit} processing={processingLogin} /> <Form onSubmit={handleSubmit} processing={processingLogin} />
<div className="login__info"> <div className="login__info">
<button type="button" className="btn btn-link login__link" onClick={toggleText}> <button type="button" className={cn(theme.link.link, 'login__link')} onClick={toggleText}>
<Trans>forgot_password</Trans> <Trans>forgot_password</Trans>
</button> </button>
@@ -41,7 +43,9 @@ export const Login = () => {
href="https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#password-reset" href="https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#password-reset"
key="0" key="0"
target="_blank" target="_blank"
rel="noopener noreferrer"> rel="noopener noreferrer"
className={theme.link.link}
>
link link
</a>, </a>,
]}> ]}>