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:
@@ -91,6 +91,7 @@ export const STANDARD_WEB_PORT = 80;
|
||||
export const STANDARD_HTTPS_PORT = 443;
|
||||
export const DNS_OVER_TLS_PORT = 853;
|
||||
export const DNS_OVER_QUIC_PORT = 853;
|
||||
export const MIN_PORT = 1;
|
||||
export const MAX_PORT = 65535;
|
||||
|
||||
export const EMPTY_DATE = '0001-01-01T00:00:00Z';
|
||||
@@ -209,7 +210,7 @@ export const WHOIS_ICONS = {
|
||||
|
||||
export const DEFAULT_LOGS_FILTER = {
|
||||
search: '',
|
||||
response_status: '',
|
||||
response_status: 'all',
|
||||
};
|
||||
|
||||
export const DEFAULT_LANGUAGE = 'en';
|
||||
|
||||
@@ -1,304 +1,5 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Trans } from 'react-i18next';
|
||||
import cn from 'classnames';
|
||||
|
||||
import { createOnBlurHandler } from './helpers';
|
||||
import { R_MAC_WITHOUT_COLON, R_UNIX_ABSOLUTE_PATH, R_WIN_ABSOLUTE_PATH } from './constants';
|
||||
|
||||
interface renderFieldProps {
|
||||
id: string;
|
||||
input: object;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
type?: string;
|
||||
disabled?: boolean;
|
||||
autoComplete?: string;
|
||||
normalizeOnBlur?: (...args: unknown[]) => unknown;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
onScroll?: (...args: unknown[]) => unknown;
|
||||
meta: {
|
||||
touched?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const renderField = (props: renderFieldProps, elementType: any) => {
|
||||
const {
|
||||
input,
|
||||
id,
|
||||
className,
|
||||
placeholder,
|
||||
type,
|
||||
disabled,
|
||||
normalizeOnBlur,
|
||||
onScroll,
|
||||
autoComplete,
|
||||
meta: { touched, error },
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
} = props;
|
||||
|
||||
const onBlur = (event: any) => createOnBlurHandler(event, input, normalizeOnBlur);
|
||||
|
||||
const element = React.createElement(elementType, {
|
||||
...input,
|
||||
id,
|
||||
className,
|
||||
placeholder,
|
||||
autoComplete,
|
||||
disabled,
|
||||
type,
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
onBlur,
|
||||
onScroll,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{element}
|
||||
{!disabled && touched && error && (
|
||||
<span className="form__message form__message--error">
|
||||
<Trans>{error}</Trans>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderTextareaField = (props: any) => renderField(props, 'textarea');
|
||||
|
||||
export const renderInputField = (props: any) => renderField(props, 'input');
|
||||
|
||||
interface renderGroupFieldProps {
|
||||
input: object;
|
||||
id?: string;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
type?: string;
|
||||
disabled?: boolean;
|
||||
autoComplete?: string;
|
||||
isActionAvailable?: boolean;
|
||||
removeField?: (...args: unknown[]) => unknown;
|
||||
meta: {
|
||||
touched?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
normalizeOnBlur?: (...args: unknown[]) => unknown;
|
||||
}
|
||||
|
||||
export const renderGroupField = ({
|
||||
input,
|
||||
id,
|
||||
className,
|
||||
placeholder,
|
||||
type,
|
||||
disabled,
|
||||
autoComplete,
|
||||
isActionAvailable,
|
||||
removeField,
|
||||
meta: { touched, error },
|
||||
normalizeOnBlur,
|
||||
}: renderGroupFieldProps) => {
|
||||
const onBlur = (event: any) => createOnBlurHandler(event, input, normalizeOnBlur);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="input-group">
|
||||
<input
|
||||
{...input}
|
||||
id={id}
|
||||
placeholder={placeholder}
|
||||
type={type}
|
||||
className={className}
|
||||
disabled={disabled}
|
||||
autoComplete={autoComplete}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
{isActionAvailable && (
|
||||
<span className="input-group-append">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary btn-icon btn-icon--green"
|
||||
onClick={removeField}>
|
||||
<svg className="icon icon--24">
|
||||
<use xlinkHref="#cross" />
|
||||
</svg>
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{!disabled && touched && error && (
|
||||
<span className="form__message form__message--error">
|
||||
<Trans>{error}</Trans>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface renderRadioFieldProps {
|
||||
input: object;
|
||||
placeholder?: string;
|
||||
subtitle?: string;
|
||||
disabled?: boolean;
|
||||
meta: {
|
||||
touched?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const renderRadioField = ({
|
||||
input,
|
||||
placeholder,
|
||||
subtitle,
|
||||
disabled,
|
||||
meta: { touched, error },
|
||||
}: renderRadioFieldProps) => (
|
||||
<Fragment>
|
||||
<label className="custom-control custom-radio">
|
||||
<input {...input} type="radio" className="custom-control-input" disabled={disabled} />
|
||||
|
||||
<span className="custom-control-label">{placeholder}</span>
|
||||
|
||||
{subtitle && <span className="checkbox__label-subtitle" dangerouslySetInnerHTML={{ __html: subtitle }} />}
|
||||
</label>
|
||||
{!disabled && touched && error && (
|
||||
<span className="form__message form__message--error">
|
||||
<Trans>{error}</Trans>
|
||||
</span>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
interface CheckboxFieldProps {
|
||||
input: object;
|
||||
placeholder?: string;
|
||||
subtitle?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
onClick?: (...args: unknown[]) => unknown;
|
||||
modifier?: string;
|
||||
checked?: boolean;
|
||||
meta: {
|
||||
touched?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const CheckboxField = ({
|
||||
input,
|
||||
placeholder,
|
||||
subtitle,
|
||||
disabled,
|
||||
onClick,
|
||||
modifier = 'checkbox--form',
|
||||
meta: { touched, error },
|
||||
}: CheckboxFieldProps) => (
|
||||
<>
|
||||
<label className={`checkbox ${modifier}`} onClick={onClick}>
|
||||
<span className="checkbox__marker" />
|
||||
|
||||
<input {...input} type="checkbox" className="checkbox__input" disabled={disabled} />
|
||||
|
||||
<span className="checkbox__label">
|
||||
<span className="checkbox__label-text checkbox__label-text--long">
|
||||
<span className="checkbox__label-title">{placeholder}</span>
|
||||
|
||||
{subtitle && <span className="checkbox__label-subtitle">{subtitle}</span>}
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
{!disabled && touched && error && (
|
||||
<div className="form__message form__message--error mt-1">
|
||||
<Trans>{error}</Trans>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
interface renderSelectFieldProps {
|
||||
input: object;
|
||||
disabled?: boolean;
|
||||
label?: string;
|
||||
children: unknown[] | React.ReactElement;
|
||||
meta: {
|
||||
touched?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const renderSelectField = ({ input, meta: { touched, error }, children, label }: renderSelectFieldProps) => {
|
||||
const showWarning = touched && error;
|
||||
|
||||
return (
|
||||
<>
|
||||
{label && (
|
||||
<label>
|
||||
<Trans>{label}</Trans>
|
||||
</label>
|
||||
)}
|
||||
|
||||
<select {...input} className="form-control custom-select">
|
||||
{children}
|
||||
</select>
|
||||
{showWarning && (
|
||||
<span className="form__message form__message--error form__message--left-pad">
|
||||
<Trans>{error}</Trans>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface renderServiceFieldProps {
|
||||
input: object;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
modifier?: string;
|
||||
icon?: string;
|
||||
meta: {
|
||||
touched?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const renderServiceField = ({
|
||||
input,
|
||||
placeholder,
|
||||
disabled,
|
||||
modifier,
|
||||
icon,
|
||||
meta: { touched, error },
|
||||
}: renderServiceFieldProps) => (
|
||||
<>
|
||||
<label className={cn('service custom-switch', { [modifier]: modifier })}>
|
||||
<input
|
||||
{...input}
|
||||
type="checkbox"
|
||||
className="custom-switch-input"
|
||||
value={placeholder.toLowerCase()}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<span className="service__switch custom-switch-indicator"></span>
|
||||
|
||||
<span className="service__text" title={placeholder}>
|
||||
{placeholder}
|
||||
</span>
|
||||
{icon && <div dangerouslySetInnerHTML={{ __html: window.atob(icon) }} className="service__icon" />}
|
||||
</label>
|
||||
{!disabled && touched && error && (
|
||||
<span className="form__message form__message--error">
|
||||
<Trans>{error}</Trans>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} ip
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
THEMES,
|
||||
} from './constants';
|
||||
import { LOCAL_STORAGE_KEYS, LocalStorageHelper } from './localStorageHelper';
|
||||
import { DhcpInterface } from '../initialState';
|
||||
import { DhcpInterface, InstallInterface } from '../initialState';
|
||||
|
||||
/**
|
||||
* @param time {string} The time to format
|
||||
@@ -217,9 +217,9 @@ export const getInterfaceIp = (option: any) => {
|
||||
return interfaceIP;
|
||||
};
|
||||
|
||||
export const getIpList = (interfaces: DhcpInterface[]) =>
|
||||
export const getIpList = (interfaces: InstallInterface[]) =>
|
||||
Object.values(interfaces)
|
||||
.reduce((acc: string[], curr: DhcpInterface) => acc.concat(curr.ip_addresses), [] as string[])
|
||||
.reduce((acc: string[], curr: InstallInterface) => acc.concat(curr.ip_addresses), [] as string[])
|
||||
.sort();
|
||||
|
||||
/**
|
||||
@@ -468,8 +468,6 @@ export const getParamsForClientsSearch = (data: any, param: any, additionalParam
|
||||
* @param {function} [normalizeOnBlur]
|
||||
* @returns {function}
|
||||
*/
|
||||
export const createOnBlurHandler = (event: any, input: any, normalizeOnBlur: any) =>
|
||||
normalizeOnBlur ? input.onBlur(normalizeOnBlur(event.target.value)) : input.onBlur();
|
||||
|
||||
export const checkFiltered = (reason: any) => reason.indexOf(FILTERED) === 0;
|
||||
export const checkRewrite = (reason: any) => reason === FILTERED_STATUS.REWRITE;
|
||||
|
||||
@@ -24,7 +24,6 @@ import { ip4ToInt, isValidAbsolutePath } from './form';
|
||||
import { isIpInCidr, parseSubnetMask } from './helpers';
|
||||
|
||||
// Validation functions
|
||||
// https://redux-form.com/8.3.0/examples/fieldlevelvalidation/
|
||||
// If the value is valid, the validation function should return undefined.
|
||||
/**
|
||||
* @param value {string|number}
|
||||
@@ -35,7 +34,7 @@ export const validateRequiredValue = (value: any) => {
|
||||
if (formattedValue || formattedValue === 0 || (formattedValue && formattedValue.length !== 0)) {
|
||||
return undefined;
|
||||
}
|
||||
return 'form_error_required';
|
||||
return i18next.t('form_error_required');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -51,7 +50,7 @@ export const validateIpv4RangeEnd = (_: any, allValues: any) => {
|
||||
const { range_end, range_start } = allValues.v4;
|
||||
|
||||
if (ip4ToInt(range_end) <= ip4ToInt(range_start)) {
|
||||
return 'greater_range_start_error';
|
||||
return i18next.t('greater_range_start_error');
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@@ -63,7 +62,7 @@ export const validateIpv4RangeEnd = (_: any, allValues: any) => {
|
||||
*/
|
||||
export const validateIpv4 = (value: any) => {
|
||||
if (value && !R_IPV4.test(value)) {
|
||||
return 'form_error_ip4_format';
|
||||
return i18next.t('form_error_ip4_format');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -108,16 +107,16 @@ export const validateNotInRange = (value: any, allValues: any) => {
|
||||
*/
|
||||
export const validateGatewaySubnetMask = (_: any, allValues: any) => {
|
||||
if (!allValues || !allValues.v4 || !allValues.v4.subnet_mask || !allValues.v4.gateway_ip) {
|
||||
return 'gateway_or_subnet_invalid';
|
||||
return i18next.t('gateway_or_subnet_invalid');
|
||||
}
|
||||
|
||||
const { subnet_mask, gateway_ip } = allValues.v4;
|
||||
|
||||
if (validateIpv4(gateway_ip)) {
|
||||
return 'gateway_or_subnet_invalid';
|
||||
return i18next.t('gateway_or_subnet_invalid');
|
||||
}
|
||||
|
||||
return parseSubnetMask(subnet_mask) ? undefined : 'gateway_or_subnet_invalid';
|
||||
return parseSubnetMask(subnet_mask) ? undefined : i18next.t('gateway_or_subnet_invalid');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -126,7 +125,7 @@ export const validateGatewaySubnetMask = (_: any, allValues: any) => {
|
||||
* @param allValues
|
||||
*/
|
||||
export const validateIpForGatewaySubnetMask = (value: any, allValues: any) => {
|
||||
if (!allValues || !allValues.v4 || !value) {
|
||||
if (!allValues || !allValues.v4 || !value || !allValues.gateway_ip || !allValues.subnet_mask) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -139,7 +138,7 @@ export const validateIpForGatewaySubnetMask = (value: any, allValues: any) => {
|
||||
const subnetPrefix = parseSubnetMask(subnet_mask);
|
||||
|
||||
if (!isIpInCidr(value, `${gateway_ip}/${subnetPrefix}`)) {
|
||||
return 'subnet_error';
|
||||
return i18next.t('subnet_error');
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@@ -149,7 +148,7 @@ export const validateIpForGatewaySubnetMask = (value: any, allValues: any) => {
|
||||
* @param value {string}
|
||||
* @returns {undefined|string}
|
||||
*/
|
||||
export const validateClientId = (value: any) => {
|
||||
export const validateClientId = (value: string) => {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -165,7 +164,7 @@ export const validateClientId = (value: any) => {
|
||||
R_CLIENT_ID.test(formattedValue)
|
||||
)
|
||||
) {
|
||||
return 'form_error_client_id_format';
|
||||
return i18next.t('form_error_client_id_format');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -180,7 +179,7 @@ export const validateConfigClientId = (value: any) => {
|
||||
}
|
||||
const formattedValue = value.trim();
|
||||
if (formattedValue && !R_CLIENT_ID.test(formattedValue)) {
|
||||
return 'form_error_client_id_format';
|
||||
return i18next.t('form_error_client_id_format');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -195,7 +194,7 @@ export const validateServerName = (value: any) => {
|
||||
}
|
||||
const formattedValue = value ? value.trim() : value;
|
||||
if (formattedValue && !R_DOMAIN.test(formattedValue)) {
|
||||
return 'form_error_server_name';
|
||||
return i18next.t('form_error_server_name');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -206,7 +205,7 @@ export const validateServerName = (value: any) => {
|
||||
*/
|
||||
export const validateIpv6 = (value: any) => {
|
||||
if (value && !R_IPV6.test(value)) {
|
||||
return 'form_error_ip6_format';
|
||||
return i18next.t('form_error_ip6_format');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -217,7 +216,7 @@ export const validateIpv6 = (value: any) => {
|
||||
*/
|
||||
export const validateIp = (value: any) => {
|
||||
if (value && !R_IPV4.test(value) && !R_IPV6.test(value)) {
|
||||
return 'form_error_ip_format';
|
||||
return i18next.t('form_error_ip_format');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -228,7 +227,7 @@ export const validateIp = (value: any) => {
|
||||
*/
|
||||
export const validateMac = (value: any) => {
|
||||
if (value && !R_MAC.test(value)) {
|
||||
return 'form_error_mac_format';
|
||||
return i18next.t('form_error_mac_format');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -239,7 +238,7 @@ export const validateMac = (value: any) => {
|
||||
*/
|
||||
export const validatePort = (value: any) => {
|
||||
if ((value || value === 0) && (value < STANDARD_WEB_PORT || value > MAX_PORT)) {
|
||||
return 'form_error_port_range';
|
||||
return i18next.t('form_error_port_range');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -250,7 +249,7 @@ export const validatePort = (value: any) => {
|
||||
*/
|
||||
export const validateInstallPort = (value: any) => {
|
||||
if (value < 1 || value > MAX_PORT) {
|
||||
return 'form_error_port';
|
||||
return i18next.t('form_error_port');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -264,7 +263,7 @@ export const validatePortTLS = (value: any) => {
|
||||
return undefined;
|
||||
}
|
||||
if (value && (value < STANDARD_WEB_PORT || value > MAX_PORT)) {
|
||||
return 'form_error_port_range';
|
||||
return i18next.t('form_error_port_range');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -281,7 +280,7 @@ export const validatePortQuic = validatePortTLS;
|
||||
*/
|
||||
export const validateIsSafePort = (value: any) => {
|
||||
if (UNSAFE_PORTS.includes(value)) {
|
||||
return 'form_error_port_unsafe';
|
||||
return i18next.t('form_error_port_unsafe');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -292,7 +291,7 @@ export const validateIsSafePort = (value: any) => {
|
||||
*/
|
||||
export const validateDomain = (value: any) => {
|
||||
if (value && !R_HOST.test(value)) {
|
||||
return 'form_error_domain_format';
|
||||
return i18next.t('form_error_domain_format');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -303,7 +302,7 @@ export const validateDomain = (value: any) => {
|
||||
*/
|
||||
export const validateAnswer = (value: any) => {
|
||||
if (value && !R_IPV4.test(value) && !R_IPV6.test(value) && !R_HOST.test(value)) {
|
||||
return 'form_error_answer_format';
|
||||
return i18next.t('form_error_answer_format');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -314,7 +313,7 @@ export const validateAnswer = (value: any) => {
|
||||
*/
|
||||
export const validatePath = (value: any) => {
|
||||
if (value && !isValidAbsolutePath(value) && !R_URL_REQUIRES_PROTOCOL.test(value)) {
|
||||
return 'form_error_url_or_path_format';
|
||||
return i18next.t('form_error_url_or_path_format');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -402,7 +401,7 @@ export const validatePlainDns = (value: any, allValues: any) => {
|
||||
const { enabled } = allValues;
|
||||
|
||||
if (!enabled && !value) {
|
||||
return 'encryption_plain_dns_error';
|
||||
return i18next.t('encryption_plain_dns_error');
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
Reference in New Issue
Block a user