mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-25 22:45:46 +03:00
- client: Allow change minimum TTL override in UI
Close #2091 #2094 #2056
Squashed commit of the following:
commit a84384bb409bfe60c4bd6477b2249c4431aa3b63
Merge: cdc5f27f a22db5f3
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Mon Sep 14 19:59:47 2020 +0300
Merge branch 'master' into fix/2091
commit cdc5f27f279f33c7d988f2927adc172e77e0a6af
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Mon Sep 14 15:41:00 2020 +0300
Fix uint32 fields validation
commit 0c6fcb90f9741ae8a33bf6c4d53bd954f2033a88
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Mon Sep 14 14:43:20 2020 +0300
Validate DNS cache configuration DNS values unit32 range
commit 1f90a1fcbc04f6c7ffb75b453e5c67e117d1c5bf
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Mon Sep 14 12:11:39 2020 +0300
Remove the limit on cache-min-ttl
commit 72e961034cc5752a50a4afc57c7be6a93d652f7d
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Fri Sep 11 16:50:19 2020 +0300
Fix translation
commit 6aebf4b87bb806ac0729b40418ba6056b3f71afa
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Fri Sep 11 12:53:01 2020 +0300
- client: Allow change minimum TTL override in UI
This commit is contained in:
parent
a22db5f358
commit
2a5b0b8da1
8 changed files with 69 additions and 78 deletions
|
@ -253,7 +253,7 @@
|
||||||
"rate_limit": "Rate limit",
|
"rate_limit": "Rate limit",
|
||||||
"edns_enable": "Enable EDNS Client Subnet",
|
"edns_enable": "Enable EDNS Client Subnet",
|
||||||
"edns_cs_desc": "If enabled, AdGuard Home will be sending clients' subnets to the DNS servers.",
|
"edns_cs_desc": "If enabled, AdGuard Home will be sending clients' subnets to the DNS servers.",
|
||||||
"rate_limit_desc": "The number of requests per second that a single client is allowed to make (0: unlimited)",
|
"rate_limit_desc": "The number of requests per second that a single client is allowed to make (setting it to 0 means unlimited)",
|
||||||
"blocking_ipv4_desc": "IP address to be returned for a blocked A request",
|
"blocking_ipv4_desc": "IP address to be returned for a blocked A request",
|
||||||
"blocking_ipv6_desc": "IP address to be returned for a blocked AAAA request",
|
"blocking_ipv6_desc": "IP address to be returned for a blocked AAAA request",
|
||||||
"blocking_mode_default": "Default: Respond with REFUSED when blocked by Adblock-style rule; respond with the IP address specified in the rule when blocked by /etc/hosts-style rule",
|
"blocking_mode_default": "Default: Respond with REFUSED when blocked by Adblock-style rule; respond with the IP address specified in the rule when blocked by /etc/hosts-style rule",
|
||||||
|
@ -564,10 +564,9 @@
|
||||||
"enter_cache_size": "Enter cache size",
|
"enter_cache_size": "Enter cache size",
|
||||||
"enter_cache_ttl_min_override": "Enter minimum TTL",
|
"enter_cache_ttl_min_override": "Enter minimum TTL",
|
||||||
"enter_cache_ttl_max_override": "Enter maximum TTL",
|
"enter_cache_ttl_max_override": "Enter maximum TTL",
|
||||||
"cache_ttl_min_override_desc": "Override TTL value (minimum) received from upstream server. This value can't larger than 3600 (1 hour)",
|
"cache_ttl_min_override_desc": "Override TTL value (minimum) received from upstream server",
|
||||||
"cache_ttl_max_override_desc": "Override TTL value (maximum) received from upstream server",
|
"cache_ttl_max_override_desc": "Override TTL value (maximum) received from upstream server",
|
||||||
"min_exceeds_max_value": "Minimum value exceeds maximum value",
|
"ttl_cache_validation": "Minimum cache TTL value must be less than or equal to the maximum value",
|
||||||
"value_not_larger_than": "Value can't be larger than {{maximum}}",
|
|
||||||
"filter_category_general": "General",
|
"filter_category_general": "General",
|
||||||
"filter_category_security": "Security",
|
"filter_category_security": "Security",
|
||||||
"filter_category_regional": "Regional",
|
"filter_category_regional": "Regional",
|
||||||
|
|
|
@ -8,10 +8,9 @@ import {
|
||||||
renderInputField,
|
renderInputField,
|
||||||
toNumber,
|
toNumber,
|
||||||
} from '../../../helpers/form';
|
} from '../../../helpers/form';
|
||||||
import { FORM_NAME } from '../../../helpers/constants';
|
import { FORM_NAME, UINT32_RANGE } from '../../../helpers/constants';
|
||||||
import {
|
import {
|
||||||
validateIpv4,
|
validateIpv4,
|
||||||
validateIsPositiveValue,
|
|
||||||
validateRequiredValue,
|
validateRequiredValue,
|
||||||
validateIpv4RangeEnd,
|
validateIpv4RangeEnd,
|
||||||
} from '../../../helpers/validators';
|
} from '../../../helpers/validators';
|
||||||
|
@ -110,9 +109,10 @@ const FormDHCPv4 = ({
|
||||||
type="number"
|
type="number"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
placeholder={t(ipv4placeholders.lease_duration)}
|
placeholder={t(ipv4placeholders.lease_duration)}
|
||||||
validate={[validateIsPositiveValue, validateRequired]}
|
validate={validateRequired}
|
||||||
normalize={toNumber}
|
normalize={toNumber}
|
||||||
min={0}
|
min={1}
|
||||||
|
max={UINT32_RANGE.MAX}
|
||||||
disabled={!isInterfaceIncludesIpv4}
|
disabled={!isInterfaceIncludesIpv4}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,12 +8,8 @@ import {
|
||||||
renderInputField,
|
renderInputField,
|
||||||
toNumber,
|
toNumber,
|
||||||
} from '../../../helpers/form';
|
} from '../../../helpers/form';
|
||||||
import { FORM_NAME } from '../../../helpers/constants';
|
import { FORM_NAME, UINT32_RANGE } from '../../../helpers/constants';
|
||||||
import {
|
import { validateIpv6, validateRequiredValue } from '../../../helpers/validators';
|
||||||
validateIpv6,
|
|
||||||
validateIsPositiveValue,
|
|
||||||
validateRequiredValue,
|
|
||||||
} from '../../../helpers/validators';
|
|
||||||
|
|
||||||
const FormDHCPv6 = ({
|
const FormDHCPv6 = ({
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
@ -86,9 +82,10 @@ const FormDHCPv6 = ({
|
||||||
type="number"
|
type="number"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
placeholder={t(ipv6placeholders.lease_duration)}
|
placeholder={t(ipv6placeholders.lease_duration)}
|
||||||
validate={[validateIsPositiveValue, validateRequired]}
|
validate={validateRequired}
|
||||||
normalizeOnBlur={toNumber}
|
normalizeOnBlur={toNumber}
|
||||||
min={0}
|
min={1}
|
||||||
|
max={UINT32_RANGE.MAX}
|
||||||
disabled={!isInterfaceIncludesIpv6}
|
disabled={!isInterfaceIncludesIpv6}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,32 +4,30 @@ import { Field, reduxForm } from 'redux-form';
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import { renderInputField, toNumber } from '../../../../helpers/form';
|
import { renderInputField, toNumber } from '../../../../helpers/form';
|
||||||
import { validateBiggerOrEqualZeroValue, getMaxValueValidator, validateRequiredValue } from '../../../../helpers/validators';
|
import { validateRequiredValue } from '../../../../helpers/validators';
|
||||||
import { FORM_NAME, SECONDS_IN_HOUR } from '../../../../helpers/constants';
|
import { CACHE_CONFIG_FIELDS, FORM_NAME, UINT32_RANGE } from '../../../../helpers/constants';
|
||||||
|
|
||||||
const validateMaxValue3600 = getMaxValueValidator(SECONDS_IN_HOUR);
|
const getInputFields = (validateRequiredValue) => [
|
||||||
|
{
|
||||||
const getInputFields = ({ validateRequiredValue, validateMaxValue3600 }) => [{
|
name: CACHE_CONFIG_FIELDS.cache_size,
|
||||||
name: 'cache_size',
|
title: 'cache_size',
|
||||||
title: 'cache_size',
|
description: 'cache_size_desc',
|
||||||
description: 'cache_size_desc',
|
placeholder: 'enter_cache_size',
|
||||||
placeholder: 'enter_cache_size',
|
validate: validateRequiredValue,
|
||||||
validate: validateRequiredValue,
|
},
|
||||||
},
|
{
|
||||||
{
|
name: CACHE_CONFIG_FIELDS.cache_ttl_min,
|
||||||
name: 'cache_ttl_min',
|
title: 'cache_ttl_min_override',
|
||||||
title: 'cache_ttl_min_override',
|
description: 'cache_ttl_min_override_desc',
|
||||||
description: 'cache_ttl_min_override_desc',
|
placeholder: 'enter_cache_ttl_min_override',
|
||||||
placeholder: 'enter_cache_ttl_min_override',
|
},
|
||||||
max: SECONDS_IN_HOUR,
|
{
|
||||||
validate: validateMaxValue3600,
|
name: CACHE_CONFIG_FIELDS.cache_ttl_max,
|
||||||
},
|
title: 'cache_ttl_max_override',
|
||||||
{
|
description: 'cache_ttl_max_override_desc',
|
||||||
name: 'cache_ttl_max',
|
placeholder: 'enter_cache_ttl_max_override',
|
||||||
title: 'cache_ttl_max_override',
|
},
|
||||||
description: 'cache_ttl_max_override_desc',
|
];
|
||||||
placeholder: 'enter_cache_ttl_max_override',
|
|
||||||
}];
|
|
||||||
|
|
||||||
const Form = ({
|
const Form = ({
|
||||||
handleSubmit, submitting, invalid,
|
handleSubmit, submitting, invalid,
|
||||||
|
@ -41,17 +39,16 @@ const Form = ({
|
||||||
cache_ttl_max, cache_ttl_min,
|
cache_ttl_max, cache_ttl_min,
|
||||||
} = useSelector((state) => state.form[FORM_NAME.CACHE].values, shallowEqual);
|
} = useSelector((state) => state.form[FORM_NAME.CACHE].values, shallowEqual);
|
||||||
|
|
||||||
const minExceedsMax = cache_ttl_min > cache_ttl_max;
|
const minExceedsMax = typeof cache_ttl_min === 'number'
|
||||||
|
&& typeof cache_ttl_max === 'number'
|
||||||
|
&& cache_ttl_min > cache_ttl_max;
|
||||||
|
|
||||||
const INPUTS_FIELDS = getInputFields({
|
const INPUTS_FIELDS = getInputFields(validateRequiredValue);
|
||||||
validateRequiredValue,
|
|
||||||
validateMaxValue3600,
|
|
||||||
});
|
|
||||||
|
|
||||||
return <form onSubmit={handleSubmit}>
|
return <form onSubmit={handleSubmit}>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{INPUTS_FIELDS.map(({
|
{INPUTS_FIELDS.map(({
|
||||||
name, title, description, placeholder, validate, max,
|
name, title, description, placeholder, validate, min = 0, max = UINT32_RANGE.MAX,
|
||||||
}) => <div className="col-12" key={name}>
|
}) => <div className="col-12" key={name}>
|
||||||
<div className="col-12 col-md-7 p-0">
|
<div className="col-12 col-md-7 p-0">
|
||||||
<div className="form__group form__group--settings">
|
<div className="form__group form__group--settings">
|
||||||
|
@ -66,15 +63,15 @@ const Form = ({
|
||||||
disabled={processingSetConfig}
|
disabled={processingSetConfig}
|
||||||
normalize={toNumber}
|
normalize={toNumber}
|
||||||
className="form-control"
|
className="form-control"
|
||||||
validate={[validateBiggerOrEqualZeroValue].concat(validate || [])}
|
validate={validate}
|
||||||
min={0}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>)}
|
</div>)}
|
||||||
{minExceedsMax
|
{minExceedsMax
|
||||||
&& <span className="text-danger pl-3 pb-3">{t('min_exceeds_max_value')}</span>}
|
&& <span className="text-danger pl-3 pb-3">{t('ttl_cache_validation')}</span>}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { change } from 'redux-form';
|
||||||
import Card from '../../../ui/Card';
|
import Card from '../../../ui/Card';
|
||||||
import Form from './Form';
|
import Form from './Form';
|
||||||
import { setDnsConfig } from '../../../../actions/dnsConfig';
|
import { setDnsConfig } from '../../../../actions/dnsConfig';
|
||||||
import { selectCompletedFields } from '../../../../helpers/helpers';
|
import { selectCompletedFields } from '../../../../helpers/helpers';
|
||||||
|
import { CACHE_CONFIG_FIELDS, FORM_NAME } from '../../../../helpers/constants';
|
||||||
|
|
||||||
const CacheConfig = () => {
|
const CacheConfig = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -15,6 +17,15 @@ const CacheConfig = () => {
|
||||||
|
|
||||||
const handleFormSubmit = (values) => {
|
const handleFormSubmit = (values) => {
|
||||||
const completedFields = selectCompletedFields(values);
|
const completedFields = selectCompletedFields(values);
|
||||||
|
|
||||||
|
Object.entries(completedFields).forEach(([k, v]) => {
|
||||||
|
if ((k === CACHE_CONFIG_FIELDS.cache_ttl_min
|
||||||
|
|| k === CACHE_CONFIG_FIELDS.cache_ttl_max)
|
||||||
|
&& v === 0) {
|
||||||
|
dispatch(change(FORM_NAME.CACHE, k, ''));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
dispatch(setDnsConfig(completedFields));
|
dispatch(setDnsConfig(completedFields));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,11 @@ import {
|
||||||
toNumber,
|
toNumber,
|
||||||
} from '../../../../helpers/form';
|
} from '../../../../helpers/form';
|
||||||
import {
|
import {
|
||||||
validateBiggerOrEqualZeroValue,
|
|
||||||
validateIpv4,
|
validateIpv4,
|
||||||
validateIpv6,
|
validateIpv6,
|
||||||
validateRequiredValue,
|
validateRequiredValue,
|
||||||
} from '../../../../helpers/validators';
|
} from '../../../../helpers/validators';
|
||||||
import { BLOCKING_MODES, FORM_NAME } from '../../../../helpers/constants';
|
import { BLOCKING_MODES, FORM_NAME, UINT32_RANGE } from '../../../../helpers/constants';
|
||||||
|
|
||||||
const checkboxes = [
|
const checkboxes = [
|
||||||
{
|
{
|
||||||
|
@ -87,7 +86,9 @@ const Form = ({
|
||||||
className="form-control"
|
className="form-control"
|
||||||
placeholder={t('form_enter_rate_limit')}
|
placeholder={t('form_enter_rate_limit')}
|
||||||
normalize={toNumber}
|
normalize={toNumber}
|
||||||
validate={[validateRequiredValue, validateBiggerOrEqualZeroValue]}
|
validate={validateRequiredValue}
|
||||||
|
min={UINT32_RANGE.MIN}
|
||||||
|
max={UINT32_RANGE.MAX}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -506,9 +506,12 @@ export const FORM_NAME = {
|
||||||
export const SMALL_SCREEN_SIZE = 767;
|
export const SMALL_SCREEN_SIZE = 767;
|
||||||
export const MEDIUM_SCREEN_SIZE = 1023;
|
export const MEDIUM_SCREEN_SIZE = 1023;
|
||||||
|
|
||||||
export const SECONDS_IN_HOUR = 60 * 60;
|
export const SECONDS_IN_DAY = 60 * 60 * 24;
|
||||||
|
|
||||||
export const SECONDS_IN_DAY = SECONDS_IN_HOUR * 24;
|
export const UINT32_RANGE = {
|
||||||
|
MIN: 0,
|
||||||
|
MAX: 4294967295,
|
||||||
|
};
|
||||||
|
|
||||||
export const DHCP_VALUES_PLACEHOLDERS = {
|
export const DHCP_VALUES_PLACEHOLDERS = {
|
||||||
ipv4: {
|
ipv4: {
|
||||||
|
@ -559,3 +562,9 @@ export const ADDRESS_TYPES = {
|
||||||
CIDR: 'CIDR',
|
CIDR: 'CIDR',
|
||||||
UNKNOWN: 'UNKNOWN',
|
UNKNOWN: 'UNKNOWN',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CACHE_CONFIG_FIELDS = {
|
||||||
|
cache_size: 'cache_size',
|
||||||
|
cache_ttl_min: 'cache_ttl_min',
|
||||||
|
cache_ttl_max: 'cache_ttl_max',
|
||||||
|
};
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import i18next from 'i18next';
|
|
||||||
import {
|
import {
|
||||||
MAX_PORT,
|
MAX_PORT,
|
||||||
R_CIDR,
|
R_CIDR,
|
||||||
|
@ -28,17 +27,6 @@ export const validateRequiredValue = (value) => {
|
||||||
return 'form_error_required';
|
return 'form_error_required';
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param maximum {number}
|
|
||||||
* @returns {(value:number) => undefined|string}
|
|
||||||
*/
|
|
||||||
export const getMaxValueValidator = (maximum) => (value) => {
|
|
||||||
if (value && value > maximum) {
|
|
||||||
return i18next.t('value_not_larger_than', { maximum });
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param value {string}
|
* @param value {string}
|
||||||
* @returns {undefined|string}
|
* @returns {undefined|string}
|
||||||
|
@ -122,17 +110,6 @@ export const validateMac = (value) => {
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param value {number}
|
|
||||||
* @returns {undefined|string}
|
|
||||||
*/
|
|
||||||
export const validateIsPositiveValue = (value) => {
|
|
||||||
if ((value || value === 0) && value <= 0) {
|
|
||||||
return 'form_error_positive';
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param value {number}
|
* @param value {number}
|
||||||
* @returns {boolean|*}
|
* @returns {boolean|*}
|
||||||
|
|
Loading…
Reference in a new issue