Pull request 2322: ADG-9415
Merge in DNS/adguard-home from ADG-9415 to master Squashed commit of the following: commit76bf99499aMerge:29529970a0389515eeAuthor: Ildar Kamalov <ik@adguard.com> Date: Wed Feb 26 18:31:41 2025 +0300 Merge branch 'master' into ADG-9415 commit29529970a3Merge:b49790daf782a1a982Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Mon Feb 24 15:44:38 2025 +0300 Merge branch 'master' into ADG-9415 commitb49790daf8Author: Ildar Kamalov <ik@adguard.com> Date: Mon Feb 24 15:30:18 2025 +0300 fix default lease duration value commitcb307472ecAuthor: Ildar Kamalov <ik@adguard.com> Date: Mon Feb 24 10:35:26 2025 +0300 fix default response status commit115e743e1aAuthor: Ildar Kamalov <ik@adguard.com> Date: Mon Feb 24 10:32:46 2025 +0300 fix upstream description commit26b0eddacaAuthor: Ildar Kamalov <ik@adguard.com> Date: Tue Feb 18 17:40:41 2025 +0300 use const for test config file commit58faa7c537Author: Ildar Kamalov <ik@adguard.com> Date: Tue Feb 18 17:31:04 2025 +0300 fix install config commit0a3346d911Author: Ildar Kamalov <ik@adguard.com> Date: Mon Feb 17 15:25:23 2025 +0300 fix install check config commit17c4c26ea8Author: Ildar Kamalov <ik@adguard.com> Date: Fri Feb 14 17:18:20 2025 +0300 fix query log commit14a2685ae3Author: Ildar Kamalov <ik@adguard.com> Date: Fri Feb 14 15:52:36 2025 +0300 fix dhcp initial values commite7a8db7afdAuthor: Ildar Kamalov <ik@adguard.com> Date: Fri Feb 14 14:37:24 2025 +0300 fix encryption form values commit1c8917f7acAuthor: Ildar Kamalov <ik@adguard.com> Date: Fri Feb 14 14:07:29 2025 +0300 fix blocked services submit commit4dfa536ceaAuthor: Ildar Kamalov <ik@adguard.com> Date: Fri Feb 14 13:50:47 2025 +0300 dns config ip validation commit4fee83fe13Author: Ildar Kamalov <ik@adguard.com> Date: Wed Feb 12 17:49:54 2025 +0300 add playwright warning commit8c2f36e7a6Author: Ildar Kamalov <ik@adguard.com> Date: Tue Feb 11 18:36:18 2025 +0300 fix config file name commit83db5f33dcAuthor: Ildar Kamalov <ik@adguard.com> Date: Tue Feb 11 16:16:43 2025 +0300 temp config file commit9080c1620fAuthor: Ildar Kamalov <ik@adguard.com> Date: Tue Feb 11 15:01:46 2025 +0300 update readme commitee1520307fMerge:fd12e33c02fe2d254bAuthor: Ildar Kamalov <ik@adguard.com> Date: Tue Feb 11 14:44:06 2025 +0300 Merge branch 'master' into ADG-9415 commitfd12e33c06Author: Igor Lobanov <bniwredyc@gmail.com> Date: Mon Feb 10 10:29:43 2025 +0100 added typecheck on build, fixed eslint commitb3849eebc4Merge:225167a8b9bf3ee128Author: Igor Lobanov <bniwredyc@gmail.com> Date: Mon Feb 10 09:43:32 2025 +0100 Merge branch 'ADG-9415' of https://bit.int.agrd.dev/scm/dns/adguard-home into ADG-9415 ... and 94 more commits
This commit is contained in:
@@ -1,118 +1,140 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
import { Field, reduxForm, formValueSelector } from 'redux-form';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
import i18next from 'i18next';
|
||||
import { CLIENT_ID_LINK } from '../../../../helpers/constants';
|
||||
import { removeEmptyLines, trimMultilineString } from '../../../../helpers/helpers';
|
||||
import { Textarea } from '../../../ui/Controls/Textarea';
|
||||
|
||||
import { renderTextareaField } from '../../../../helpers/form';
|
||||
import { trimMultilineString, removeEmptyLines } from '../../../../helpers/helpers';
|
||||
import { CLIENT_ID_LINK, FORM_NAME } from '../../../../helpers/constants';
|
||||
type FormData = {
|
||||
allowed_clients: string;
|
||||
disallowed_clients: string;
|
||||
blocked_hosts: string;
|
||||
};
|
||||
|
||||
const fields = [
|
||||
const fields: {
|
||||
id: keyof FormData;
|
||||
title: string;
|
||||
subtitle: ReactNode;
|
||||
normalizeOnBlur: (value: string) => string;
|
||||
}[] = [
|
||||
{
|
||||
id: 'allowed_clients',
|
||||
title: 'access_allowed_title',
|
||||
subtitle: 'access_allowed_desc',
|
||||
title: i18next.t('access_allowed_title'),
|
||||
subtitle: (
|
||||
<Trans
|
||||
components={{
|
||||
a: <a href={CLIENT_ID_LINK} target="_blank" rel="noopener noreferrer" />,
|
||||
}}>
|
||||
access_allowed_desc
|
||||
</Trans>
|
||||
),
|
||||
normalizeOnBlur: removeEmptyLines,
|
||||
},
|
||||
{
|
||||
id: 'disallowed_clients',
|
||||
title: 'access_disallowed_title',
|
||||
subtitle: 'access_disallowed_desc',
|
||||
title: i18next.t('access_disallowed_title'),
|
||||
subtitle: (
|
||||
<Trans
|
||||
components={{
|
||||
a: <a href={CLIENT_ID_LINK} target="_blank" rel="noopener noreferrer" />,
|
||||
}}>
|
||||
access_disallowed_desc
|
||||
</Trans>
|
||||
),
|
||||
normalizeOnBlur: trimMultilineString,
|
||||
},
|
||||
{
|
||||
id: 'blocked_hosts',
|
||||
title: 'access_blocked_title',
|
||||
subtitle: 'access_blocked_desc',
|
||||
title: i18next.t('access_blocked_title'),
|
||||
subtitle: i18next.t('access_blocked_desc'),
|
||||
normalizeOnBlur: removeEmptyLines,
|
||||
},
|
||||
];
|
||||
|
||||
interface FormProps {
|
||||
handleSubmit: (...args: unknown[]) => string;
|
||||
submitting: boolean;
|
||||
invalid: boolean;
|
||||
initialValues: object;
|
||||
type FormProps = {
|
||||
initialValues?: {
|
||||
allowed_clients?: string;
|
||||
disallowed_clients?: string;
|
||||
blocked_hosts?: string;
|
||||
};
|
||||
onSubmit: (data: FormData) => void;
|
||||
processingSet: boolean;
|
||||
t: (...args: unknown[]) => string;
|
||||
textarea?: boolean;
|
||||
allowedClients?: string;
|
||||
}
|
||||
};
|
||||
|
||||
interface renderFieldProps {
|
||||
id?: string;
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
disabled?: boolean;
|
||||
processingSet?: boolean;
|
||||
normalizeOnBlur?: (...args: unknown[]) => unknown;
|
||||
}
|
||||
const Form = ({ initialValues, onSubmit, processingSet }: FormProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
let Form = (props: FormProps) => {
|
||||
const { allowedClients, handleSubmit, submitting, invalid, processingSet } = props;
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
watch,
|
||||
formState: { isSubmitting, isDirty },
|
||||
} = useForm<FormData>({
|
||||
mode: 'onBlur',
|
||||
defaultValues: {
|
||||
allowed_clients: initialValues?.allowed_clients || '',
|
||||
disallowed_clients: initialValues?.disallowed_clients || '',
|
||||
blocked_hosts: initialValues?.blocked_hosts || '',
|
||||
},
|
||||
});
|
||||
|
||||
const allowedClients = watch('allowed_clients');
|
||||
|
||||
const renderField = ({
|
||||
id,
|
||||
title,
|
||||
subtitle,
|
||||
disabled = false,
|
||||
processingSet,
|
||||
normalizeOnBlur,
|
||||
}: renderFieldProps) => (
|
||||
<div key={id} className="form__group mb-5">
|
||||
<label className="form__label form__label--with-desc" htmlFor={id}>
|
||||
<Trans>{title}</Trans>
|
||||
}: {
|
||||
id: keyof FormData;
|
||||
title: string;
|
||||
subtitle: ReactNode;
|
||||
normalizeOnBlur: (value: string) => string;
|
||||
}) => {
|
||||
const disabled = allowedClients && id === 'disallowed_clients';
|
||||
|
||||
{disabled && (
|
||||
<>
|
||||
<span> </span>(<Trans>disabled</Trans>)
|
||||
</>
|
||||
)}
|
||||
</label>
|
||||
return (
|
||||
<div key={id} className="form__group mb-5">
|
||||
<label className="form__label form__label--with-desc" htmlFor={id}>
|
||||
{title}
|
||||
{disabled && <> ({t('disabled')})</>}
|
||||
</label>
|
||||
|
||||
<div className="form__desc form__desc--top">
|
||||
<Trans
|
||||
components={{
|
||||
a: (
|
||||
<a href={CLIENT_ID_LINK} target="_blank" rel="noopener noreferrer">
|
||||
text
|
||||
</a>
|
||||
),
|
||||
}}>
|
||||
{subtitle}
|
||||
</Trans>
|
||||
<div className="form__desc form__desc--top">{subtitle}</div>
|
||||
|
||||
<Controller
|
||||
name={id}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Textarea
|
||||
{...field}
|
||||
id={id}
|
||||
data-testid={id}
|
||||
disabled={disabled || processingSet}
|
||||
onBlur={(e) => {
|
||||
field.onChange(normalizeOnBlur(e.target.value));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Field
|
||||
id={id}
|
||||
name={id}
|
||||
component={renderTextareaField}
|
||||
type="text"
|
||||
className="form-control form-control--textarea font-monospace"
|
||||
disabled={disabled || processingSet}
|
||||
normalizeOnBlur={normalizeOnBlur}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
{fields.map((f) => {
|
||||
return renderField({
|
||||
...f,
|
||||
disabled: allowedClients && f.id === 'disallowed_clients' || false
|
||||
});
|
||||
})}
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{fields.map((f) => renderField(f))}
|
||||
|
||||
<div className="card-actions">
|
||||
<div className="btn-list">
|
||||
<button
|
||||
type="submit"
|
||||
data-testid="access_save"
|
||||
className="btn btn-success btn-standard"
|
||||
disabled={submitting || invalid || processingSet}>
|
||||
<Trans>save_config</Trans>
|
||||
disabled={isSubmitting || !isDirty || processingSet}>
|
||||
{t('save_config')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -120,18 +142,4 @@ let Form = (props: FormProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const selector = formValueSelector(FORM_NAME.ACCESS);
|
||||
|
||||
Form = connect((state) => {
|
||||
const allowedClients = selector(state, 'allowed_clients');
|
||||
return {
|
||||
allowedClients,
|
||||
};
|
||||
})(Form);
|
||||
|
||||
export default flow([
|
||||
withTranslation(),
|
||||
reduxForm({
|
||||
form: FORM_NAME.ACCESS,
|
||||
}),
|
||||
])(Form);
|
||||
export default Form;
|
||||
|
||||
Reference in New Issue
Block a user