diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 73f5db5b..baa0d353 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -3,6 +3,8 @@ "example_upstream_reserved": "You can specify DNS upstream <0>for the specific domain(s)</0>", "upstream_parallel": "Use parallel requests to speed up resolving by simultaneously querying all upstream servers", "parallel_requests": "Parallel requests", + "load_balancing": "Load-balancing", + "load_balancing_desc": "Query one server at a time. AdGuard Home will use the weighted random algorithm to pick the server so that the fastest server will be used more often.", "bootstrap_dns": "Bootstrap DNS servers", "bootstrap_dns_desc": "Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams.", "check_dhcp_servers": "Check for DHCP servers", diff --git a/client/src/components/Filters/Check/index.js b/client/src/components/Filters/Check/index.js index 463bb4a5..a15b62aa 100644 --- a/client/src/components/Filters/Check/index.js +++ b/client/src/components/Filters/Check/index.js @@ -7,6 +7,7 @@ import Card from '../../ui/Card'; import { renderInputField } from '../../../helpers/form'; import Info from './Info'; +import { FORM_NAME } from '../../../helpers/constants'; const Check = (props) => { const { @@ -60,7 +61,7 @@ const Check = (props) => { </div> {check.hostname && ( <Fragment> - <hr/> + <hr /> <Info filters={filters} whitelistFilters={whitelistFilters} @@ -94,5 +95,5 @@ Check.propTypes = { export default flow([ withTranslation(), - reduxForm({ form: 'domainCheckForm' }), + reduxForm({ form: FORM_NAME.DOMAIN_CHECK }), ])(Check); diff --git a/client/src/components/Filters/Form.js b/client/src/components/Filters/Form.js index 7fc1f0a6..46e0579d 100644 --- a/client/src/components/Filters/Form.js +++ b/client/src/components/Filters/Form.js @@ -5,6 +5,7 @@ import { Trans, withTranslation } from 'react-i18next'; import flow from 'lodash/flow'; import { renderInputField, required, isValidPath } from '../../helpers/form'; +import { FORM_NAME } from '../../helpers/constants'; const Form = (props) => { const { @@ -19,18 +20,18 @@ const Form = (props) => { return ( <form onSubmit={handleSubmit}> <div className="modal-body"> - <div className="form__group"> - <Field - id="name" - name="name" - type="text" - component={renderInputField} - className="form-control" - placeholder={t('enter_name_hint')} - validate={[required]} - normalizeOnBlur={(data) => data.trim()} - /> - </div> + <div className="form__group"> + <Field + id="name" + name="name" + type="text" + component={renderInputField} + className="form-control" + placeholder={t('enter_name_hint')} + validate={[required]} + normalizeOnBlur={(data) => data.trim()} + /> + </div> <div className="form__group"> <Field id="url" @@ -79,7 +80,5 @@ Form.propTypes = { export default flow([ withTranslation(), - reduxForm({ - form: 'filterForm', - }), + reduxForm({ form: FORM_NAME.FILTER }), ])(Form); diff --git a/client/src/components/Filters/Rewrites/Form.js b/client/src/components/Filters/Rewrites/Form.js index 0e5de03e..5382ee32 100644 --- a/client/src/components/Filters/Rewrites/Form.js +++ b/client/src/components/Filters/Rewrites/Form.js @@ -7,6 +7,7 @@ import flow from 'lodash/flow'; import { renderInputField, required, domain, answer, } from '../../../helpers/form'; +import { FORM_NAME } from '../../../helpers/constants'; const Form = (props) => { const { @@ -104,7 +105,7 @@ Form.propTypes = { export default flow([ withTranslation(), reduxForm({ - form: 'rewritesForm', + form: FORM_NAME.REWRITES, enableReinitialize: true, }), ])(Form); diff --git a/client/src/components/Filters/Services/Form.js b/client/src/components/Filters/Services/Form.js index 1b2b499a..4aed810d 100644 --- a/client/src/components/Filters/Services/Form.js +++ b/client/src/components/Filters/Services/Form.js @@ -6,7 +6,7 @@ import flow from 'lodash/flow'; import { toggleAllServices } from '../../../helpers/helpers'; import { renderServiceField } from '../../../helpers/form'; -import { SERVICES } from '../../../helpers/constants'; +import { FORM_NAME, SERVICES } from '../../../helpers/constants'; const Form = (props) => { const { @@ -84,7 +84,7 @@ Form.propTypes = { export default flow([ withTranslation(), reduxForm({ - form: 'servicesForm', + form: FORM_NAME.SERVICES, enableReinitialize: true, }), ])(Form); diff --git a/client/src/components/Logs/Filters/Form.js b/client/src/components/Logs/Filters/Form.js index 307694cb..9a10442f 100644 --- a/client/src/components/Logs/Filters/Form.js +++ b/client/src/components/Logs/Filters/Form.js @@ -5,7 +5,7 @@ import { withTranslation } from 'react-i18next'; import flow from 'lodash/flow'; import { renderInputField } from '../../../helpers/form'; -import { RESPONSE_FILTER } from '../../../helpers/constants'; +import { FORM_NAME, RESPONSE_FILTER } from '../../../helpers/constants'; import Tooltip from '../../ui/Tooltip'; const renderFilterField = ({ @@ -124,6 +124,6 @@ Form.propTypes = { export default flow([ withTranslation(), reduxForm({ - form: 'logsFilterForm', + form: FORM_NAME.LOGS_FILTER, }), ])(Form); diff --git a/client/src/components/Settings/Clients/Form.js b/client/src/components/Settings/Clients/Form.js index 5ac8faf8..5b2a49c4 100644 --- a/client/src/components/Settings/Clients/Form.js +++ b/client/src/components/Settings/Clients/Form.js @@ -20,7 +20,7 @@ import { renderSelectField, renderServiceField, } from '../../../helpers/form'; -import { SERVICES } from '../../../helpers/constants'; +import { FORM_NAME, SERVICES } from '../../../helpers/constants'; import './Service.css'; const settingsCheckboxes = [ @@ -338,7 +338,7 @@ Form.propTypes = { tagsOptions: PropTypes.array.isRequired, }; -const selector = formValueSelector('clientForm'); +const selector = formValueSelector(FORM_NAME.CLIENT); Form = connect((state) => { const useGlobalSettings = selector(state, 'use_global_settings'); @@ -352,7 +352,7 @@ Form = connect((state) => { export default flow([ withTranslation(), reduxForm({ - form: 'clientForm', + form: FORM_NAME.CLIENT, enableReinitialize: true, validate, }), diff --git a/client/src/components/Settings/Dhcp/Form.js b/client/src/components/Settings/Dhcp/Form.js index b319b495..6e0a134f 100644 --- a/client/src/components/Settings/Dhcp/Form.js +++ b/client/src/components/Settings/Dhcp/Form.js @@ -8,6 +8,7 @@ import flow from 'lodash/flow'; import { renderInputField, required, ipv4, isPositive, toNumber, } from '../../../helpers/form'; +import { FORM_NAME } from '../../../helpers/constants'; const renderInterfaces = ((interfaces) => ( Object.keys(interfaces).map((item) => { @@ -221,7 +222,7 @@ Form.propTypes = { change: PropTypes.func.isRequired, }; -const selector = formValueSelector('dhcpForm'); +const selector = formValueSelector(FORM_NAME.DHCP); Form = connect((state) => { const interfaceValue = selector(state, 'interface_name'); @@ -232,5 +233,5 @@ Form = connect((state) => { export default flow([ withTranslation(), - reduxForm({ form: 'dhcpForm' }), + reduxForm({ form: FORM_NAME.DHCP }), ])(Form); diff --git a/client/src/components/Settings/Dhcp/StaticLeases/Form.js b/client/src/components/Settings/Dhcp/StaticLeases/Form.js index b2924d78..9cbbb0a2 100644 --- a/client/src/components/Settings/Dhcp/StaticLeases/Form.js +++ b/client/src/components/Settings/Dhcp/StaticLeases/Form.js @@ -7,6 +7,7 @@ import flow from 'lodash/flow'; import { renderInputField, ipv4, mac, required, } from '../../../../helpers/form'; +import { FORM_NAME } from '../../../../helpers/constants'; const Form = (props) => { const { @@ -94,5 +95,5 @@ Form.propTypes = { export default flow([ withTranslation(), - reduxForm({ form: 'leaseForm' }), + reduxForm({ form: FORM_NAME.LEASE }), ])(Form); diff --git a/client/src/components/Settings/Dns/Access/Form.js b/client/src/components/Settings/Dns/Access/Form.js index 7cdec77a..bd7ca897 100644 --- a/client/src/components/Settings/Dns/Access/Form.js +++ b/client/src/components/Settings/Dns/Access/Form.js @@ -5,6 +5,7 @@ import { Trans, withTranslation } from 'react-i18next'; import flow from 'lodash/flow'; import { renderTextareaField } from '../../../../helpers/form'; import { normalizeMultiline } from '../../../../helpers/helpers'; +import { FORM_NAME } from '../../../../helpers/constants'; const fields = [ { @@ -84,4 +85,4 @@ Form.propTypes = { textarea: PropTypes.bool, }; -export default flow([withTranslation(), reduxForm({ form: 'accessForm' })])(Form); +export default flow([withTranslation(), reduxForm({ form: FORM_NAME.ACCESS })])(Form); diff --git a/client/src/components/Settings/Dns/Config/Form.js b/client/src/components/Settings/Dns/Config/Form.js index e24655e3..a137130e 100644 --- a/client/src/components/Settings/Dns/Config/Form.js +++ b/client/src/components/Settings/Dns/Config/Form.js @@ -15,7 +15,7 @@ import { biggerOrEqualZero, toNumber, } from '../../../../helpers/form'; -import { BLOCKING_MODES } from '../../../../helpers/constants'; +import { BLOCKING_MODES, FORM_NAME } from '../../../../helpers/constants'; const checkboxes = [{ name: 'edns_cs_enabled', @@ -60,91 +60,91 @@ const getFields = (processing, t) => Object.values(BLOCKING_MODES) let Form = ({ handleSubmit, submitting, invalid, processing, blockingMode, t, }) => <form onSubmit={handleSubmit}> - <div className="row"> - <div className="col-12 col-sm-6"> - <div className="form__group form__group--settings"> - <label htmlFor="ratelimit" - className="form__label form__label--with-desc"> - <Trans>rate_limit</Trans> - </label> - <div className="form__desc form__desc--top"> - <Trans>rate_limit_desc</Trans> - </div> - <Field - name="ratelimit" - type="number" - component={renderInputField} - className="form-control" - placeholder={t('form_enter_rate_limit')} - normalize={toNumber} - validate={[required, biggerOrEqualZero]} - /> + <div className="row"> + <div className="col-12 col-sm-6"> + <div className="form__group form__group--settings"> + <label htmlFor="ratelimit" + className="form__label form__label--with-desc"> + <Trans>rate_limit</Trans> + </label> + <div className="form__desc form__desc--top"> + <Trans>rate_limit_desc</Trans> + </div> + <Field + name="ratelimit" + type="number" + component={renderInputField} + className="form-control" + placeholder={t('form_enter_rate_limit')} + normalize={toNumber} + validate={[required, biggerOrEqualZero]} + /> + </div> + </div> + {checkboxes.map(({ name, placeholder, subtitle }) => <div className="col-12" key={name}> + <div className="form__group form__group--settings"> + <Field + name={name} + type="checkbox" + component={renderSelectField} + placeholder={t(placeholder)} + disabled={processing} + subtitle={t(subtitle)} + /> + </div> + </div>)} + <div className="col-12"> + <div className="form__group form__group--settings mb-4"> + <label className="form__label form__label--with-desc"> + <Trans>blocking_mode</Trans> + </label> + <div className="form__desc form__desc--top"> + {Object.values(BLOCKING_MODES) + .map((mode) => ( + <li key={mode}> + <Trans>{`blocking_mode_${mode}`}</Trans> + </li> + ))} + </div> + <div className="custom-controls-stacked"> + {getFields(processing, t)} </div> </div> - {checkboxes.map(({ name, placeholder, subtitle }) => <div className="col-12" key={name}> + </div> + {blockingMode === BLOCKING_MODES.custom_ip && ( + <Fragment> + {customIps.map(({ + description, + name, + validateIp, + }) => <div className="col-12 col-sm-6" key={name}> <div className="form__group form__group--settings"> + <label className="form__label form__label--with-desc" + htmlFor={name}><Trans>{name}</Trans> + </label> + <div className="form__desc form__desc--top"> + <Trans>{description}</Trans> + </div> <Field name={name} - type="checkbox" - component={renderSelectField} - placeholder={t(placeholder)} - disabled={processing} - subtitle={t(subtitle)} + component={renderInputField} + className="form-control" + placeholder={t('form_enter_ip')} + validate={[validateIp, required]} /> </div> </div>)} - <div className="col-12"> - <div className="form__group form__group--settings mb-4"> - <label className="form__label form__label--with-desc"> - <Trans>blocking_mode</Trans> - </label> - <div className="form__desc form__desc--top"> - {Object.values(BLOCKING_MODES) - .map((mode) => ( - <li key={mode}> - <Trans>{`blocking_mode_${mode}`}</Trans> - </li> - ))} - </div> - <div className="custom-controls-stacked"> - {getFields(processing, t)} - </div> - </div> - </div> - {blockingMode === BLOCKING_MODES.custom_ip && ( - <Fragment> - {customIps.map(({ - description, - name, - validateIp, - }) => <div className="col-12 col-sm-6" key={name}> - <div className="form__group form__group--settings"> - <label className="form__label form__label--with-desc" - htmlFor={name}><Trans>{name}</Trans> - </label> - <div className="form__desc form__desc--top"> - <Trans>{description}</Trans> - </div> - <Field - name={name} - component={renderInputField} - className="form-control" - placeholder={t('form_enter_ip')} - validate={[validateIp, required]} - /> - </div> - </div>)} - </Fragment> - )} - </div> - <button - type="submit" - className="btn btn-success btn-standard btn-large" - disabled={submitting || invalid || processing} - > - <Trans>save_btn</Trans> - </button> - </form>; + </Fragment> + )} + </div> + <button + type="submit" + className="btn btn-success btn-standard btn-large" + disabled={submitting || invalid || processing} + > + <Trans>save_btn</Trans> + </button> +</form>; Form.propTypes = { blockingMode: PropTypes.string.isRequired, @@ -155,7 +155,7 @@ Form.propTypes = { t: PropTypes.func.isRequired, }; -const selector = formValueSelector('blockingModeForm'); +const selector = formValueSelector(FORM_NAME.BLOCKING_MODE); Form = connect((state) => { const blockingMode = selector(state, 'blocking_mode'); @@ -166,7 +166,5 @@ Form = connect((state) => { export default flow([ withTranslation(), - reduxForm({ - form: 'blockingModeForm', - }), + reduxForm({ form: FORM_NAME.BLOCKING_MODE }), ])(Form); diff --git a/client/src/components/Settings/Dns/Upstream/Form.js b/client/src/components/Settings/Dns/Upstream/Form.js index ec110d6d..99ae9a95 100644 --- a/client/src/components/Settings/Dns/Upstream/Form.js +++ b/client/src/components/Settings/Dns/Upstream/Form.js @@ -1,14 +1,14 @@ import React from 'react'; -import { connect } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import PropTypes from 'prop-types'; -import { Field, reduxForm, formValueSelector } from 'redux-form'; -import { Trans, withTranslation } from 'react-i18next'; -import flow from 'lodash/flow'; +import { Field, reduxForm } from 'redux-form'; +import { Trans, useTranslation } from 'react-i18next'; import classnames from 'classnames'; import Examples from './Examples'; import { renderRadioField } from '../../../../helpers/form'; -import { DNS_REQUEST_OPTIONS } from '../../../../helpers/constants'; +import { DNS_REQUEST_OPTIONS, FORM_NAME } from '../../../../helpers/constants'; +import { testUpstream } from '../../../../actions'; const getInputFields = () => [{ // eslint-disable-next-line react/display-name @@ -22,15 +22,23 @@ const getInputFields = () => [{ placeholder: 'upstream_dns', }, { - name: 'dnsRequestOption', + name: 'upstream_mode', type: 'radio', - value: DNS_REQUEST_OPTIONS.PARALLEL_REQUESTS, + value: DNS_REQUEST_OPTIONS.LOAD_BALANCING, + component: renderRadioField, + subtitle: 'load_balancing_desc', + placeholder: 'load_balancing', +}, +{ + name: 'upstream_mode', + type: 'radio', + value: DNS_REQUEST_OPTIONS.PARALLEL, component: renderRadioField, subtitle: 'upstream_parallel', placeholder: 'parallel_requests', }, { - name: 'dnsRequestOption', + name: 'upstream_mode', type: 'radio', value: DNS_REQUEST_OPTIONS.FASTEST_ADDR, component: renderRadioField, @@ -38,22 +46,22 @@ const getInputFields = () => [{ placeholder: 'fastest_addr', }]; -let Form = (props) => { - const { - t, - handleSubmit, - testUpstream, - submitting, - invalid, - processingSetConfig, - processingTestUpstream, +const Form = ({ + submitting, invalid, processingSetConfig, processingTestUpstream, handleSubmit, +}) => { + const dispatch = useDispatch(); + const [t] = useTranslation(); + const upstream_dns = useSelector((store) => store.form[FORM_NAME.UPSTREAM].values.upstream_dns); + const bootstrap_dns = useSelector((store) => store.form[FORM_NAME.UPSTREAM] + .values.bootstrap_dns); + + const handleUpstreamTest = () => dispatch(testUpstream({ upstream_dns, bootstrap_dns, - } = props; + })); - const testButtonClass = classnames({ - 'btn btn-primary btn-standard mr-2': true, - 'btn btn-primary btn-standard mr-2 btn-loading': processingTestUpstream, + const testButtonClass = classnames('btn btn-primary btn-standard mr-2', { + 'btn-loading': processingTestUpstream, }); const INPUT_FIELDS = getInputFields(); @@ -106,11 +114,7 @@ let Form = (props) => { <button type="button" className={testButtonClass} - onClick={() => testUpstream({ - upstream_dns, - bootstrap_dns, - }) - } + onClick={handleUpstreamTest} disabled={!upstream_dns || processingTestUpstream} > <Trans>test_upstream_btn</Trans> @@ -131,7 +135,6 @@ let Form = (props) => { Form.propTypes = { handleSubmit: PropTypes.func, - testUpstream: PropTypes.func, submitting: PropTypes.bool, invalid: PropTypes.bool, initialValues: PropTypes.object, @@ -139,24 +142,6 @@ Form.propTypes = { bootstrap_dns: PropTypes.string, processingTestUpstream: PropTypes.bool, processingSetConfig: PropTypes.bool, - t: PropTypes.func, }; -const selector = formValueSelector('upstreamForm'); - -Form = connect((state) => { - const upstream_dns = selector(state, 'upstream_dns'); - const bootstrap_dns = selector(state, 'bootstrap_dns'); - - return { - upstream_dns, - bootstrap_dns, - }; -})(Form); - -export default flow([ - withTranslation(), - reduxForm({ - form: 'upstreamForm', - }), -])(Form); +export default reduxForm({ form: FORM_NAME.UPSTREAM })(Form); diff --git a/client/src/components/Settings/Dns/Upstream/index.js b/client/src/components/Settings/Dns/Upstream/index.js index 4a849d49..55dcdc67 100644 --- a/client/src/components/Settings/Dns/Upstream/index.js +++ b/client/src/components/Settings/Dns/Upstream/index.js @@ -1,83 +1,56 @@ -import React, { Component } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; -import { withTranslation } from 'react-i18next'; -import cn from 'classnames'; - +import { useTranslation } from 'react-i18next'; +import { useDispatch } from 'react-redux'; import Form from './Form'; import Card from '../../../ui/Card'; -import { DNS_REQUEST_OPTIONS } from '../../../../helpers/constants'; +import { setDnsConfig } from '../../../../actions/dnsConfig'; +const Upstream = (props) => { + const [t] = useTranslation(); + const dispatch = useDispatch(); -class Upstream extends Component { - handleSubmit = ({ bootstrap_dns, upstream_dns, dnsRequestOption }) => { - const disabledOption = dnsRequestOption === DNS_REQUEST_OPTIONS.PARALLEL_REQUESTS - ? DNS_REQUEST_OPTIONS.FASTEST_ADDR - : DNS_REQUEST_OPTIONS.PARALLEL_REQUESTS; + const handleSubmit = (values) => { + dispatch(setDnsConfig(values)); + }; - const formattedValues = { - bootstrap_dns, + const { + processingTestUpstream, + dnsConfig: { upstream_dns, - [dnsRequestOption]: true, - [disabledOption]: false, - }; + bootstrap_dns, + processingSetConfig, + upstream_mode, + }, + } = props; - this.props.setDnsConfig(formattedValues); - }; - - handleTest = (values) => { - this.props.testUpstream(values); - }; - - render() { - const { - t, - processingTestUpstream, - dnsConfig: { - upstream_dns, - bootstrap_dns, - fastest_addr, - parallel_requests, - processingSetConfig, - }, - } = this.props; - - const dnsRequestOption = cn({ - parallel_requests, - fastest_addr, - }); - - return ( - <Card - title={t('upstream_dns')} - subtitle={t('upstream_dns_hint')} - bodyType="card-body box-body--settings" - > - <div className="row"> - <div className="col"> - <Form - initialValues={{ - upstream_dns, - bootstrap_dns, - dnsRequestOption, - }} - testUpstream={this.handleTest} - onSubmit={this.handleSubmit} - processingTestUpstream={processingTestUpstream} - processingSetConfig={processingSetConfig} - /> - </div> + return ( + <Card + title={t('upstream_dns')} + subtitle={t('upstream_dns_hint')} + bodyType="card-body box-body--settings" + > + <div className="row"> + <div className="col"> + <Form + initialValues={{ + upstream_dns, + bootstrap_dns, + upstream_mode, + }} + onSubmit={handleSubmit} + processingTestUpstream={processingTestUpstream} + processingSetConfig={processingSetConfig} + /> </div> - </Card> - ); - } -} - -Upstream.propTypes = { - testUpstream: PropTypes.func.isRequired, - processingTestUpstream: PropTypes.bool.isRequired, - t: PropTypes.func.isRequired, - dnsConfig: PropTypes.object.isRequired, - setDnsConfig: PropTypes.func.isRequired, + </div> + </Card> + ); }; -export default withTranslation()(Upstream); +Upstream.propTypes = { + processingTestUpstream: PropTypes.bool.isRequired, + dnsConfig: PropTypes.object.isRequired, +}; + +export default Upstream; diff --git a/client/src/components/Settings/Dns/index.js b/client/src/components/Settings/Dns/index.js index db9d0613..5ed8f9ca 100644 --- a/client/src/components/Settings/Dns/index.js +++ b/client/src/components/Settings/Dns/index.js @@ -1,6 +1,6 @@ -import React, { Component, Fragment } from 'react'; +import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; -import { withTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; import Upstream from './Upstream'; import Access from './Access'; @@ -8,58 +8,52 @@ import Config from './Config'; import PageTitle from '../../ui/PageTitle'; import Loading from '../../ui/Loading'; -class Dns extends Component { - componentDidMount() { - this.props.getAccessList(); - this.props.getDnsConfig(); - } +const Dns = (props) => { + const [t] = useTranslation(); - render() { - const { - t, - settings, - access, - setAccessList, - testUpstream, - dnsConfig, - setDnsConfig, - } = this.props; + useEffect(() => { + props.getAccessList(); + props.getDnsConfig(); + }, []); - const isDataLoading = access.processing || dnsConfig.processingGetConfig; + const { + settings, + access, + setAccessList, + dnsConfig, + setDnsConfig, + } = props; - return ( - <Fragment> - <PageTitle title={t('dns_settings')} /> - {isDataLoading - ? <Loading /> - : <Fragment> - <Upstream - processingTestUpstream={settings.processingTestUpstream} - testUpstream={testUpstream} - dnsConfig={dnsConfig} - setDnsConfig={setDnsConfig} - /> - <Config - dnsConfig={dnsConfig} - setDnsConfig={setDnsConfig} - /> - <Access access={access} setAccessList={setAccessList} /> - </Fragment>} - </Fragment> - ); - } -} + const isDataLoading = access.processing || dnsConfig.processingGetConfig; + + return ( + <> + <PageTitle title={t('dns_settings')} /> + {isDataLoading + ? <Loading /> + : <> + <Upstream + processingTestUpstream={settings.processingTestUpstream} + dnsConfig={dnsConfig} + /> + <Config + dnsConfig={dnsConfig} + setDnsConfig={setDnsConfig} + /> + <Access access={access} setAccessList={setAccessList} /> + </>} + </> + ); +}; Dns.propTypes = { settings: PropTypes.object.isRequired, - testUpstream: PropTypes.func.isRequired, getAccessList: PropTypes.func.isRequired, setAccessList: PropTypes.func.isRequired, access: PropTypes.object.isRequired, dnsConfig: PropTypes.object.isRequired, setDnsConfig: PropTypes.func.isRequired, getDnsConfig: PropTypes.func.isRequired, - t: PropTypes.func.isRequired, }; -export default withTranslation()(Dns); +export default Dns; diff --git a/client/src/components/Settings/Encryption/Form.js b/client/src/components/Settings/Encryption/Form.js index 6fb9fd7b..69186b0b 100644 --- a/client/src/components/Settings/Encryption/Form.js +++ b/client/src/components/Settings/Encryption/Form.js @@ -17,6 +17,7 @@ import { import i18n from '../../../i18n'; import KeyStatus from './KeyStatus'; import CertificateStatus from './CertificateStatus'; +import { FORM_NAME } from '../../../helpers/constants'; const validate = (values) => { const errors = {}; @@ -394,7 +395,7 @@ Form.propTypes = { privateKeySource: PropTypes.string, }; -const selector = formValueSelector('encryptionForm'); +const selector = formValueSelector(FORM_NAME.ENCRYPTION); Form = connect((state) => { const isEnabled = selector(state, 'enabled'); @@ -418,7 +419,7 @@ Form = connect((state) => { export default flow([ withTranslation(), reduxForm({ - form: 'encryptionForm', + form: FORM_NAME.ENCRYPTION, validate, }), ])(Form); diff --git a/client/src/components/Settings/FiltersConfig/Form.js b/client/src/components/Settings/FiltersConfig/Form.js index d08196bf..73ec77f0 100644 --- a/client/src/components/Settings/FiltersConfig/Form.js +++ b/client/src/components/Settings/FiltersConfig/Form.js @@ -5,12 +5,13 @@ import { Trans, withTranslation } from 'react-i18next'; import flow from 'lodash/flow'; import { renderSelectField, toNumber } from '../../../helpers/form'; -import { FILTERS_INTERVALS_HOURS } from '../../../helpers/constants'; +import { FILTERS_INTERVALS_HOURS, FORM_NAME } from '../../../helpers/constants'; const getTitleForInterval = (interval, t) => { if (interval === 0) { return t('disabled'); - } if (interval === 72 || interval === 168) { + } + if (interval === 72 || interval === 168) { return t('interval_days', { count: interval / 24 }); } @@ -81,7 +82,5 @@ Form.propTypes = { export default flow([ withTranslation(), - reduxForm({ - form: 'filterConfigForm', - }), + reduxForm({ form: FORM_NAME.FILTER_CONFIG }), ])(Form); diff --git a/client/src/components/Settings/LogsConfig/Form.js b/client/src/components/Settings/LogsConfig/Form.js index 351139aa..74454bac 100644 --- a/client/src/components/Settings/LogsConfig/Form.js +++ b/client/src/components/Settings/LogsConfig/Form.js @@ -5,22 +5,22 @@ import { Trans, withTranslation } from 'react-i18next'; import flow from 'lodash/flow'; import { renderSelectField, renderRadioField, toNumber } from '../../../helpers/form'; -import { QUERY_LOG_INTERVALS_DAYS } from '../../../helpers/constants'; +import { FORM_NAME, QUERY_LOG_INTERVALS_DAYS } from '../../../helpers/constants'; const getIntervalFields = (processing, t, toNumber) => QUERY_LOG_INTERVALS_DAYS.map((interval) => { const title = interval === 1 ? t('interval_24_hour') : t('interval_days', { count: interval }); return ( - <Field - key={interval} - name="interval" - type="radio" - component={renderRadioField} - value={interval} - placeholder={title} - normalize={toNumber} - disabled={processing} - /> + <Field + key={interval} + name="interval" + type="radio" + component={renderRadioField} + value={interval} + placeholder={title} + normalize={toNumber} + disabled={processing} + /> ); }); @@ -91,7 +91,5 @@ Form.propTypes = { export default flow([ withTranslation(), - reduxForm({ - form: 'logConfigForm', - }), + reduxForm({ form: FORM_NAME.LOG_CONFIG }), ])(Form); diff --git a/client/src/components/Settings/StatsConfig/Form.js b/client/src/components/Settings/StatsConfig/Form.js index 472700c2..53b34f4b 100644 --- a/client/src/components/Settings/StatsConfig/Form.js +++ b/client/src/components/Settings/StatsConfig/Form.js @@ -5,22 +5,22 @@ import { Trans, withTranslation } from 'react-i18next'; import flow from 'lodash/flow'; import { renderRadioField, toNumber } from '../../../helpers/form'; -import { STATS_INTERVALS_DAYS } from '../../../helpers/constants'; +import { FORM_NAME, STATS_INTERVALS_DAYS } from '../../../helpers/constants'; const getIntervalFields = (processing, t, toNumber) => STATS_INTERVALS_DAYS.map((interval) => { const title = interval === 1 ? t('interval_24_hour') : t('interval_days', { count: interval }); return ( - <Field - key={interval} - name="interval" - type="radio" - component={renderRadioField} - value={interval} - placeholder={title} - normalize={toNumber} - disabled={processing} - /> + <Field + key={interval} + name="interval" + type="radio" + component={renderRadioField} + value={interval} + placeholder={title} + normalize={toNumber} + disabled={processing} + /> ); }); @@ -76,7 +76,5 @@ Form.propTypes = { export default flow([ withTranslation(), - reduxForm({ - form: 'statsConfigForm', - }), + reduxForm({ form: FORM_NAME.STATS_CONFIG }), ])(Form); diff --git a/client/src/containers/Dns.js b/client/src/containers/Dns.js index 961c2f3e..54cdb30c 100644 --- a/client/src/containers/Dns.js +++ b/client/src/containers/Dns.js @@ -1,5 +1,4 @@ import { connect } from 'react-redux'; -import { testUpstream } from '../actions'; import { getAccessList, setAccessList } from '../actions/access'; import { getRewritesList, @@ -25,7 +24,6 @@ const mapStateToProps = (state) => { }; const mapDispatchToProps = { - testUpstream, getAccessList, setAccessList, getRewritesList, diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index dea07dbf..60c22264 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -377,12 +377,33 @@ export const ACTION = { }; export const DNS_REQUEST_OPTIONS = { - PARALLEL_REQUESTS: 'parallel_requests', + PARALLEL: 'parallel', FASTEST_ADDR: 'fastest_addr', + LOAD_BALANCING: '', }; export const IP_MATCH_LIST_STATUS = { NOT_FOUND: 'NOT_FOUND', // not found in the list - EXACT: 'EXACT', // found exact match (ip === ip) + EXACT: 'EXACT', // found exact match (including the match of short and long forms) CIDR: 'CIDR', // the ip is in the specified CIDR range }; + +export const FORM_NAME = { + UPSTREAM: 'upstream', + DOMAIN_CHECK: 'domainCheck', + FILTER: 'filter', + REWRITES: 'rewrites', + LOGS_FILTER: 'logsFilter', + CLIENT: 'client', + DHCP: 'dhcp', + LEASE: 'lease', + ACCESS: 'access', + BLOCKING_MODE: 'blockingMode', + ENCRYPTION: 'encryption', + FILTER_CONFIG: 'filterConfig', + LOG_CONFIG: 'logConfig', + SERVICES: 'services', + STATS_CONFIG: 'statsConfig', + INSTALL: 'install', + LOGIN: 'login', +}; diff --git a/client/src/install/Setup/Auth.js b/client/src/install/Setup/Auth.js index 4a502573..b4184191 100644 --- a/client/src/install/Setup/Auth.js +++ b/client/src/install/Setup/Auth.js @@ -7,6 +7,7 @@ import flow from 'lodash/flow'; import i18n from '../../i18n'; import Controls from './Controls'; import { renderInputField } from '../../helpers/form'; +import { FORM_NAME } from '../../helpers/constants'; const required = (value) => { if (value || value === 0) { @@ -100,7 +101,7 @@ Auth.propTypes = { export default flow([ withTranslation(), reduxForm({ - form: 'install', + form: FORM_NAME.INSTALL, destroyOnUnmount: false, forceUnregisterOnUnmount: true, validate, diff --git a/client/src/install/Setup/Devices.js b/client/src/install/Setup/Devices.js index 9e92e381..59f25dea 100644 --- a/client/src/install/Setup/Devices.js +++ b/client/src/install/Setup/Devices.js @@ -8,6 +8,7 @@ import flow from 'lodash/flow'; import Guide from '../../components/ui/Guide'; import Controls from './Controls'; import AddressList from './AddressList'; +import { FORM_NAME } from '../../helpers/constants'; let Devices = (props) => ( <div className="setup__step"> @@ -56,7 +57,7 @@ Devices = connect((state) => { export default flow([ withTranslation(), reduxForm({ - form: 'install', + form: FORM_NAME.INSTALL, destroyOnUnmount: false, forceUnregisterOnUnmount: true, }), diff --git a/client/src/install/Setup/Settings.js b/client/src/install/Setup/Settings.js index b7e8f9ee..afafcf34 100644 --- a/client/src/install/Setup/Settings.js +++ b/client/src/install/Setup/Settings.js @@ -9,7 +9,7 @@ import Controls from './Controls'; import AddressList from './AddressList'; import { getInterfaceIp } from '../../helpers/helpers'; -import { ALL_INTERFACES_IP } from '../../helpers/constants'; +import { ALL_INTERFACES_IP, FORM_NAME } from '../../helpers/constants'; import { renderInputField, required, validInstallPort, toNumber, } from '../../helpers/form'; @@ -373,7 +373,7 @@ Settings.propTypes = { t: PropTypes.func.isRequired, }; -const selector = formValueSelector('install'); +const selector = formValueSelector(FORM_NAME.INSTALL); const SettingsForm = connect((state) => { const webIp = selector(state, 'web.ip'); @@ -392,7 +392,7 @@ const SettingsForm = connect((state) => { export default flow([ withTranslation(), reduxForm({ - form: 'install', + form: FORM_NAME.INSTALL, destroyOnUnmount: false, forceUnregisterOnUnmount: true, }), diff --git a/client/src/install/Setup/Submit.js b/client/src/install/Setup/Submit.js index 863c8045..d3c9f555 100644 --- a/client/src/install/Setup/Submit.js +++ b/client/src/install/Setup/Submit.js @@ -6,6 +6,7 @@ import { Trans, withTranslation } from 'react-i18next'; import flow from 'lodash/flow'; import Controls from './Controls'; +import { FORM_NAME } from '../../helpers/constants'; let Submit = (props) => ( <div className="setup__step"> @@ -50,7 +51,7 @@ Submit = connect((state) => { export default flow([ withTranslation(), reduxForm({ - form: 'install', + form: FORM_NAME.INSTALL, destroyOnUnmount: false, forceUnregisterOnUnmount: true, }), diff --git a/client/src/login/Login/Form.js b/client/src/login/Login/Form.js index d3d825d7..4d8cfdd3 100644 --- a/client/src/login/Login/Form.js +++ b/client/src/login/Login/Form.js @@ -5,6 +5,7 @@ import { Trans, withTranslation } from 'react-i18next'; import flow from 'lodash/flow'; import { renderInputField, required } from '../../helpers/form'; +import { FORM_NAME } from '../../helpers/constants'; const Form = (props) => { const { @@ -70,7 +71,5 @@ Form.propTypes = { export default flow([ withTranslation(), - reduxForm({ - form: 'loginForm', - }), + reduxForm({ form: FORM_NAME.LOGIN }), ])(Form);