From 2a5b0b8da1f85727e36a4601c51bdfb79ef2583f Mon Sep 17 00:00:00 2001 From: Artem Baskal <a.baskal@adguard.com> Date: Mon, 14 Sep 2020 20:16:46 +0300 Subject: [PATCH 1/2] - 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 --- client/src/__locales/en.json | 7 +- .../components/Settings/Dhcp/FormDHCPv4.js | 8 +-- .../components/Settings/Dhcp/FormDHCPv6.js | 13 ++-- .../src/components/Settings/Dns/Cache/Form.js | 65 +++++++++---------- .../components/Settings/Dns/Cache/index.js | 11 ++++ .../components/Settings/Dns/Config/Form.js | 7 +- client/src/helpers/constants.js | 13 +++- client/src/helpers/validators.js | 23 ------- 8 files changed, 69 insertions(+), 78 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index ece13f64..a5e0208b 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -253,7 +253,7 @@ "rate_limit": "Rate limit", "edns_enable": "Enable EDNS Client Subnet", "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_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", @@ -564,10 +564,9 @@ "enter_cache_size": "Enter cache size", "enter_cache_ttl_min_override": "Enter minimum 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", - "min_exceeds_max_value": "Minimum value exceeds maximum value", - "value_not_larger_than": "Value can't be larger than {{maximum}}", + "ttl_cache_validation": "Minimum cache TTL value must be less than or equal to the maximum value", "filter_category_general": "General", "filter_category_security": "Security", "filter_category_regional": "Regional", diff --git a/client/src/components/Settings/Dhcp/FormDHCPv4.js b/client/src/components/Settings/Dhcp/FormDHCPv4.js index b938b6f0..873e7696 100644 --- a/client/src/components/Settings/Dhcp/FormDHCPv4.js +++ b/client/src/components/Settings/Dhcp/FormDHCPv4.js @@ -8,10 +8,9 @@ import { renderInputField, toNumber, } from '../../../helpers/form'; -import { FORM_NAME } from '../../../helpers/constants'; +import { FORM_NAME, UINT32_RANGE } from '../../../helpers/constants'; import { validateIpv4, - validateIsPositiveValue, validateRequiredValue, validateIpv4RangeEnd, } from '../../../helpers/validators'; @@ -110,9 +109,10 @@ const FormDHCPv4 = ({ type="number" className="form-control" placeholder={t(ipv4placeholders.lease_duration)} - validate={[validateIsPositiveValue, validateRequired]} + validate={validateRequired} normalize={toNumber} - min={0} + min={1} + max={UINT32_RANGE.MAX} disabled={!isInterfaceIncludesIpv4} /> </div> diff --git a/client/src/components/Settings/Dhcp/FormDHCPv6.js b/client/src/components/Settings/Dhcp/FormDHCPv6.js index 80219fd6..e37a6213 100644 --- a/client/src/components/Settings/Dhcp/FormDHCPv6.js +++ b/client/src/components/Settings/Dhcp/FormDHCPv6.js @@ -8,12 +8,8 @@ import { renderInputField, toNumber, } from '../../../helpers/form'; -import { FORM_NAME } from '../../../helpers/constants'; -import { - validateIpv6, - validateIsPositiveValue, - validateRequiredValue, -} from '../../../helpers/validators'; +import { FORM_NAME, UINT32_RANGE } from '../../../helpers/constants'; +import { validateIpv6, validateRequiredValue } from '../../../helpers/validators'; const FormDHCPv6 = ({ handleSubmit, @@ -86,9 +82,10 @@ const FormDHCPv6 = ({ type="number" className="form-control" placeholder={t(ipv6placeholders.lease_duration)} - validate={[validateIsPositiveValue, validateRequired]} + validate={validateRequired} normalizeOnBlur={toNumber} - min={0} + min={1} + max={UINT32_RANGE.MAX} disabled={!isInterfaceIncludesIpv6} /> </div> diff --git a/client/src/components/Settings/Dns/Cache/Form.js b/client/src/components/Settings/Dns/Cache/Form.js index c7b2d6ed..f17310c9 100644 --- a/client/src/components/Settings/Dns/Cache/Form.js +++ b/client/src/components/Settings/Dns/Cache/Form.js @@ -4,32 +4,30 @@ import { Field, reduxForm } from 'redux-form'; import { Trans, useTranslation } from 'react-i18next'; import { shallowEqual, useSelector } from 'react-redux'; import { renderInputField, toNumber } from '../../../../helpers/form'; -import { validateBiggerOrEqualZeroValue, getMaxValueValidator, validateRequiredValue } from '../../../../helpers/validators'; -import { FORM_NAME, SECONDS_IN_HOUR } from '../../../../helpers/constants'; +import { validateRequiredValue } from '../../../../helpers/validators'; +import { CACHE_CONFIG_FIELDS, FORM_NAME, UINT32_RANGE } from '../../../../helpers/constants'; -const validateMaxValue3600 = getMaxValueValidator(SECONDS_IN_HOUR); - -const getInputFields = ({ validateRequiredValue, validateMaxValue3600 }) => [{ - name: 'cache_size', - title: 'cache_size', - description: 'cache_size_desc', - placeholder: 'enter_cache_size', - validate: validateRequiredValue, -}, -{ - name: 'cache_ttl_min', - title: 'cache_ttl_min_override', - description: 'cache_ttl_min_override_desc', - placeholder: 'enter_cache_ttl_min_override', - max: SECONDS_IN_HOUR, - validate: validateMaxValue3600, -}, -{ - name: 'cache_ttl_max', - title: 'cache_ttl_max_override', - description: 'cache_ttl_max_override_desc', - placeholder: 'enter_cache_ttl_max_override', -}]; +const getInputFields = (validateRequiredValue) => [ + { + name: CACHE_CONFIG_FIELDS.cache_size, + title: 'cache_size', + description: 'cache_size_desc', + placeholder: 'enter_cache_size', + validate: validateRequiredValue, + }, + { + name: CACHE_CONFIG_FIELDS.cache_ttl_min, + title: 'cache_ttl_min_override', + description: 'cache_ttl_min_override_desc', + placeholder: 'enter_cache_ttl_min_override', + }, + { + name: CACHE_CONFIG_FIELDS.cache_ttl_max, + title: 'cache_ttl_max_override', + description: 'cache_ttl_max_override_desc', + placeholder: 'enter_cache_ttl_max_override', + }, +]; const Form = ({ handleSubmit, submitting, invalid, @@ -41,17 +39,16 @@ const Form = ({ cache_ttl_max, cache_ttl_min, } = 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({ - validateRequiredValue, - validateMaxValue3600, - }); + const INPUTS_FIELDS = getInputFields(validateRequiredValue); return <form onSubmit={handleSubmit}> <div className="row"> {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 col-md-7 p-0"> <div className="form__group form__group--settings"> @@ -66,15 +63,15 @@ const Form = ({ disabled={processingSetConfig} normalize={toNumber} className="form-control" - validate={[validateBiggerOrEqualZeroValue].concat(validate || [])} - min={0} + validate={validate} + min={min} max={max} /> </div> </div> </div>)} {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> <button type="submit" diff --git a/client/src/components/Settings/Dns/Cache/index.js b/client/src/components/Settings/Dns/Cache/index.js index 22b8b7b6..391c17e9 100644 --- a/client/src/components/Settings/Dns/Cache/index.js +++ b/client/src/components/Settings/Dns/Cache/index.js @@ -1,10 +1,12 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; +import { change } from 'redux-form'; import Card from '../../../ui/Card'; import Form from './Form'; import { setDnsConfig } from '../../../../actions/dnsConfig'; import { selectCompletedFields } from '../../../../helpers/helpers'; +import { CACHE_CONFIG_FIELDS, FORM_NAME } from '../../../../helpers/constants'; const CacheConfig = () => { const { t } = useTranslation(); @@ -15,6 +17,15 @@ const CacheConfig = () => { const handleFormSubmit = (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)); }; diff --git a/client/src/components/Settings/Dns/Config/Form.js b/client/src/components/Settings/Dns/Config/Form.js index 0d4a23ee..ecdd2439 100644 --- a/client/src/components/Settings/Dns/Config/Form.js +++ b/client/src/components/Settings/Dns/Config/Form.js @@ -10,12 +10,11 @@ import { toNumber, } from '../../../../helpers/form'; import { - validateBiggerOrEqualZeroValue, validateIpv4, validateIpv6, validateRequiredValue, } from '../../../../helpers/validators'; -import { BLOCKING_MODES, FORM_NAME } from '../../../../helpers/constants'; +import { BLOCKING_MODES, FORM_NAME, UINT32_RANGE } from '../../../../helpers/constants'; const checkboxes = [ { @@ -87,7 +86,9 @@ const Form = ({ className="form-control" placeholder={t('form_enter_rate_limit')} normalize={toNumber} - validate={[validateRequiredValue, validateBiggerOrEqualZeroValue]} + validate={validateRequiredValue} + min={UINT32_RANGE.MIN} + max={UINT32_RANGE.MAX} /> </div> </div> diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index 86ed844d..2ab176ea 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -506,9 +506,12 @@ export const FORM_NAME = { export const SMALL_SCREEN_SIZE = 767; 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 = { ipv4: { @@ -559,3 +562,9 @@ export const ADDRESS_TYPES = { CIDR: 'CIDR', UNKNOWN: 'UNKNOWN', }; + +export const CACHE_CONFIG_FIELDS = { + cache_size: 'cache_size', + cache_ttl_min: 'cache_ttl_min', + cache_ttl_max: 'cache_ttl_max', +}; diff --git a/client/src/helpers/validators.js b/client/src/helpers/validators.js index 64c5fa49..9b853120 100644 --- a/client/src/helpers/validators.js +++ b/client/src/helpers/validators.js @@ -1,4 +1,3 @@ -import i18next from 'i18next'; import { MAX_PORT, R_CIDR, @@ -28,17 +27,6 @@ export const validateRequiredValue = (value) => { 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} * @returns {undefined|string} @@ -122,17 +110,6 @@ export const validateMac = (value) => { 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} * @returns {boolean|*} From 96512433477a6b32ac4e51e73899f82dc1c2a6e1 Mon Sep 17 00:00:00 2001 From: Artem Baskal <a.baskal@adguard.com> Date: Tue, 15 Sep 2020 10:30:34 +0300 Subject: [PATCH 2/2] - client: Make dashboard card height constant Close #2039 Squashed commit of the following: commit 1d6dd461558403ea0ba813d5f665ecbaab9cd8ed Merge: 6ca80c91 2a5b0b8d Author: ArtemBaskal <a.baskal@adguard.com> Date: Tue Sep 15 10:18:19 2020 +0300 Merge branch 'master' into fix/2039 commit 6ca80c9171da61a4bc02cec409299d0cfb96da49 Author: ArtemBaskal <a.baskal@adguard.com> Date: Mon Sep 14 19:58:43 2020 +0300 Fix mobile media query commit 239c9ab29aaaef200bd2289fa116507ea5c2bf4c Author: ArtemBaskal <a.baskal@adguard.com> Date: Mon Sep 14 13:59:39 2020 +0300 - client: Make dashboard card height constant --- client/src/components/Dashboard/index.js | 3 +-- client/src/components/ui/Card.css | 8 +++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/client/src/components/Dashboard/index.js b/client/src/components/Dashboard/index.js index 07d8f94f..4d229ffb 100644 --- a/client/src/components/Dashboard/index.js +++ b/client/src/components/Dashboard/index.js @@ -82,7 +82,7 @@ const Dashboard = ({ </div> </PageTitle> {statsProcessing && <Loading />} - {!statsProcessing && <div className="row row-cards"> + {!statsProcessing && <div className="row row-cards dashboard"> <div className="col-lg-12"> <Statistics interval={stats.interval} @@ -100,7 +100,6 @@ const Dashboard = ({ <div className="col-lg-6"> <Counters subtitle={subtitle} - refreshButton={refreshButton} /> </div> diff --git a/client/src/components/ui/Card.css b/client/src/components/ui/Card.css index 5930d881..eb8a7963 100644 --- a/client/src/components/ui/Card.css +++ b/client/src/components/ui/Card.css @@ -19,7 +19,7 @@ max-height: 17.5rem; } -.card-table-overflow--limited.clients__table { +.dashboard .card-table-overflow--limited { max-height: 18rem; } @@ -122,6 +122,12 @@ } } +@media (min-width: 992px) { + .dashboard .card:not(.card--full) { + height: 22rem; + } +} + .card .logs__cell--red { background-color: #fff4f2; }