Pull request: 2842 DHCP validation ui

Closes #2842.

Squashed commit of the following:

commit 8580db9d3fd6bdd906bf53ca3696fc497f7573b8
Merge: a5d7187b ab85ad5a
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Apr 13 15:29:06 2021 +0300

    Merge branch 'master' into 2842-dhcp-validation-ui

commit a5d7187bba1ae3595bbc26a362ff27aae81a7048
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Apr 13 15:08:28 2021 +0300

    fix: revert deleted translation

commit 50169266111032f6de3bc159ba562ee9580532fb
Merge: 46adf2c0 48d702f7
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Apr 13 14:39:40 2021 +0300

    Merge branch 'master' into 2842-dhcp-validation-ui

commit 46adf2c05b6bedd55e60475eac060347db6572b7
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Apr 13 14:13:12 2021 +0300

    fix: no-bitwise

commit 1afc4030a5ea885545e51748976724959f87fb26
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Apr 13 13:57:43 2021 +0300

    fix: IPv4 in CIDR validation

commit 2035a3f6a2d7026b9055bab64a265ac1b56abd74
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Apr 13 11:58:03 2021 +0300

    fix: translations

commit 6dd455f7dbf92987663b433b7cb8e21c9d0e5b82
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Apr 13 11:57:27 2021 +0300

    fix: MAC validation

commit 281e49a2e2b974e0c7eb89547661aed8238a5d0c
Merge: 48b50ce9 65553a29
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Apr 6 18:12:06 2021 +0300

    Merge branch 'master' into 2842-dhcp-validation-ui

commit 48b50ce9ce84479c43c3d6fc824853dc0b17ac1e
Author: Artem Baskal <a.baskal@adguard.com>
Date:   Mon Apr 5 19:04:35 2021 +0300

    Add leases ip validation

commit 8630f3bf5f03451c3a49c4ce4ebee3a86d16b6a1
Author: Artem Baskal <a.baskal@adguard.com>
Date:   Mon Apr 5 13:59:16 2021 +0300

    Add helper for subnet to bitmap mask conversion, write test

commit 80dc7a8d19b27cecc50e2c610619574374f363d3
Author: Artem Baskal <a.baskal@adguard.com>
Date:   Fri Apr 2 17:46:27 2021 +0300

    2842 Update DHCP range validation in UI
This commit is contained in:
Ainar Garipov
2021-04-13 15:29:28 +03:00
parent ab85ad5a55
commit 327e76cd65
10 changed files with 152 additions and 12 deletions

View File

@@ -3,8 +3,14 @@ import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form';
import { Trans, useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { renderInputField } from '../../../../helpers/form';
import { validateIpv4, validateMac, validateRequiredValue } from '../../../../helpers/validators';
import { renderInputField, normalizeMac } from '../../../../helpers/form';
import {
validateIpv4,
validateMac,
validateRequiredValue,
validateIpv4InCidr,
} from '../../../../helpers/validators';
import { FORM_NAME } from '../../../../helpers/constants';
import { toggleLeaseModal } from '../../../../actions';
@@ -14,6 +20,7 @@ const Form = ({
pristine,
submitting,
processingAdding,
cidr,
}) => {
const { t } = useTranslation();
const dispatch = useDispatch();
@@ -34,6 +41,7 @@ const Form = ({
type="text"
className="form-control"
placeholder={t('form_enter_mac')}
normalize={normalizeMac}
validate={[validateRequiredValue, validateMac]}
/>
</div>
@@ -44,8 +52,8 @@ const Form = ({
component={renderInputField}
type="text"
className="form-control"
placeholder={t('form_enter_ip')}
validate={[validateRequiredValue, validateIpv4]}
placeholder={t('form_enter_subnet_ip', { cidr })}
validate={[validateRequiredValue, validateIpv4, validateIpv4InCidr]}
/>
</div>
<div className="form__group">
@@ -84,11 +92,18 @@ const Form = ({
};
Form.propTypes = {
initialValues: PropTypes.shape({
mac: PropTypes.string.isRequired,
ip: PropTypes.string.isRequired,
hostname: PropTypes.string.isRequired,
cidr: PropTypes.string.isRequired,
}),
pristine: PropTypes.bool.isRequired,
handleSubmit: PropTypes.func.isRequired,
reset: PropTypes.func.isRequired,
submitting: PropTypes.bool.isRequired,
processingAdding: PropTypes.bool.isRequired,
cidr: PropTypes.string.isRequired,
};
export default reduxForm({ form: FORM_NAME.LEASE })(Form);

View File

@@ -10,6 +10,7 @@ const Modal = ({
isModalOpen,
handleSubmit,
processingAdding,
cidr,
}) => {
const dispatch = useDispatch();
@@ -32,8 +33,15 @@ const Modal = ({
</button>
</div>
<Form
initialValues={{
mac: '',
ip: '',
hostname: '',
cidr,
}}
onSubmit={handleSubmit}
processingAdding={processingAdding}
cidr={cidr}
/>
</div>
</ReactModal>
@@ -44,6 +52,7 @@ Modal.propTypes = {
isModalOpen: PropTypes.bool.isRequired,
handleSubmit: PropTypes.func.isRequired,
processingAdding: PropTypes.bool.isRequired,
cidr: PropTypes.string.isRequired,
};
export default withTranslation()(Modal);

View File

@@ -21,12 +21,14 @@ const StaticLeases = ({
processingAdding,
processingDeleting,
staticLeases,
cidr,
}) => {
const [t] = useTranslation();
const dispatch = useDispatch();
const handleSubmit = (data) => {
dispatch(addStaticLease(data));
const { mac, ip, hostname } = data;
dispatch(addStaticLease({ mac, ip, hostname }));
};
const handleDelete = (ip, mac, hostname = '') => {
@@ -97,6 +99,7 @@ const StaticLeases = ({
isModalOpen={isModalOpen}
handleSubmit={handleSubmit}
processingAdding={processingAdding}
cidr={cidr}
/>
</>
);
@@ -107,6 +110,7 @@ StaticLeases.propTypes = {
isModalOpen: PropTypes.bool.isRequired,
processingAdding: PropTypes.bool.isRequired,
processingDeleting: PropTypes.bool.isRequired,
cidr: PropTypes.string.isRequired,
};
cellWrap.propTypes = {

View File

@@ -30,6 +30,7 @@ import Interfaces from './Interfaces';
import {
calculateDhcpPlaceholdersIpv4,
calculateDhcpPlaceholdersIpv6,
subnetMaskToBitMask,
} from '../../../helpers/helpers';
import './index.css';
@@ -59,6 +60,10 @@ const Dhcp = () => {
const interface_name = useSelector(
(state) => state.form[FORM_NAME.DHCP_INTERFACES]?.values?.interface_name,
);
const isInterfaceIncludesIpv4 = useSelector(
(state) => !!state.dhcp?.interfaces?.[interface_name]?.ipv4_addresses,
);
const dhcp = useSelector((state) => state.form[FORM_NAME.DHCPv4], shallowEqual);
const [ipv4placeholders, setIpv4Placeholders] = useState(DHCP_DESCRIPTION_PLACEHOLDERS.ipv4);
const [ipv6placeholders, setIpv6Placeholders] = useState(DHCP_DESCRIPTION_PLACEHOLDERS.ipv6);
@@ -173,6 +178,12 @@ const Dhcp = () => {
const toggleDhcpButton = getToggleDhcpButton();
const inputtedIPv4values = dhcp?.values?.v4?.gateway_ip && dhcp?.values?.v4?.subnet_mask;
const isEmptyConfig = !Object.values(dhcp?.values?.v4 ?? {}).some(Boolean);
const disabledLeasesButton = dhcp?.syncErrors || interfaces?.syncErrors
|| !isInterfaceIncludesIpv4 || isEmptyConfig || processingConfig || !inputtedIPv4values;
const cidr = inputtedIPv4values ? `${dhcp?.values?.v4?.gateway_ip}/${subnetMaskToBitMask(dhcp?.values?.v4?.subnet_mask)}` : '';
return <>
<PageTitle title={t('dhcp_settings')} subtitle={t('dhcp_description')} containerClass="page-title--dhcp">
{toggleDhcpButton}
@@ -256,6 +267,7 @@ const Dhcp = () => {
isModalOpen={isModalOpen}
processingAdding={processingAdding}
processingDeleting={processingDeleting}
cidr={cidr}
/>
</div>
<div className="col-12">
@@ -263,6 +275,7 @@ const Dhcp = () => {
type="button"
className="btn btn-success btn-standard mt-3"
onClick={toggleModal}
disabled={disabledLeasesButton}
>
<Trans>dhcp_add_static_lease</Trans>
</button>