From f736d85e6e96a3d67cb0ec22e27c0b549f3292e9 Mon Sep 17 00:00:00 2001
From: Vladislav Abdulmyanov <v.abdulmyanov@adguard.com>
Date: Tue, 21 Mar 2023 14:42:54 +0300
Subject: [PATCH] Pull request 1776: client: add transform dynamic lease to
 static

Updates #3459.

Squashed commit of the following:

commit 7a660c689da898c125a268f88378e38a58b457da
Author: Vladislav Abdulmyanov <v.abdulmyanov@adguard.com>
Date:   Tue Mar 21 10:40:25 2023 +0200

    consider issues

commit 066bf77ac44fa8602c66aa0ea220b52fca6d1180
Author: Vladislav Abdulmyanov <v.abdulmyanov@adguard.com>
Date:   Mon Mar 20 18:37:14 2023 +0200

    client: fix icon

commit 356b4c3895436f165697510bb3b3abf95f18894f
Author: Vladislav Abdulmyanov <v.abdulmyanov@adguard.com>
Date:   Mon Mar 20 18:32:03 2023 +0200

    client: add transform dinamic lease to static
---
 client/src/__locales/en.json                  |  3 +-
 client/src/components/Settings/Dhcp/Leases.js | 37 +++++++++++++++++--
 .../Settings/Dhcp/StaticLeases/Form.js        |  5 ++-
 .../Settings/Dhcp/StaticLeases/Modal.js       | 11 ++++--
 .../Settings/Dhcp/StaticLeases/index.js       |  2 +-
 client/src/components/Settings/Dhcp/index.js  |  6 +--
 client/src/reducers/dhcp.js                   |  4 +-
 7 files changed, 53 insertions(+), 15 deletions(-)

diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json
index 2afa38bd..ee0345d7 100644
--- a/client/src/__locales/en.json
+++ b/client/src/__locales/en.json
@@ -642,5 +642,6 @@
     "anonymizer_notification": "<0>Note:</0> IP anonymization is enabled. You can disable it in <1>General settings</1>.",
     "confirm_dns_cache_clear": "Are you sure you want to clear DNS cache?",
     "cache_cleared": "DNS cache successfully cleared",
-    "clear_cache": "Clear cache"
+    "clear_cache": "Clear cache",
+    "make_static": "Make static"
 }
diff --git a/client/src/components/Settings/Dhcp/Leases.js b/client/src/components/Settings/Dhcp/Leases.js
index 2973d1b5..96ca8852 100644
--- a/client/src/components/Settings/Dhcp/Leases.js
+++ b/client/src/components/Settings/Dhcp/Leases.js
@@ -1,9 +1,11 @@
 import React, { Component } from 'react';
+import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ReactTable from 'react-table';
 import { Trans, withTranslation } from 'react-i18next';
 import { LEASES_TABLE_DEFAULT_PAGE_SIZE } from '../../../helpers/constants';
 import { sortIp } from '../../../helpers/helpers';
+import { toggleLeaseModal } from '../../../actions';
 
 class Leases extends Component {
     cellWrap = ({ value }) => (
@@ -14,6 +16,30 @@ class Leases extends Component {
         </div>
     );
 
+    convertToStatic = (data) => () => {
+        const { dispatch } = this.props;
+        dispatch(toggleLeaseModal(data));
+    }
+
+    makeStatic = ({ row }) => {
+        const { t, disabledLeasesButton } = this.props;
+        return (
+            <div className="logs__row logs__row--center">
+                <button
+                    type="button"
+                    className="btn btn-icon btn-icon--green btn-outline-secondary btn-sm"
+                    title={t('make_static')}
+                    onClick={this.convertToStatic(row)}
+                    disabled={disabledLeasesButton}
+                >
+                    <svg className="icons icon12">
+                        <use xlinkHref="#plus" />
+                    </svg>
+                </button>
+            </div>
+        );
+    }
+
     render() {
         const { leases, t } = this.props;
         return (
@@ -23,7 +49,7 @@ class Leases extends Component {
                     {
                         Header: 'MAC',
                         accessor: 'mac',
-                        minWidth: 160,
+                        minWidth: 180,
                         Cell: this.cellWrap,
                     }, {
                         Header: 'IP',
@@ -39,8 +65,11 @@ class Leases extends Component {
                     }, {
                         Header: <Trans>dhcp_table_expires</Trans>,
                         accessor: 'expires',
-                        minWidth: 130,
+                        minWidth: 220,
                         Cell: this.cellWrap,
+                    }, {
+                        Header: <Trans>actions_table_header</Trans>,
+                        Cell: this.makeStatic,
                     },
                 ]}
                 pageSize={LEASES_TABLE_DEFAULT_PAGE_SIZE}
@@ -57,6 +86,8 @@ class Leases extends Component {
 Leases.propTypes = {
     leases: PropTypes.array,
     t: PropTypes.func,
+    dispatch: PropTypes.func,
+    disabledLeasesButton: PropTypes.bool,
 };
 
-export default withTranslation()(Leases);
+export default withTranslation()(connect(() => ({}), (dispatch) => ({ dispatch }))(Leases));
diff --git a/client/src/components/Settings/Dhcp/StaticLeases/Form.js b/client/src/components/Settings/Dhcp/StaticLeases/Form.js
index 0525f6a3..e26b4da5 100644
--- a/client/src/components/Settings/Dhcp/StaticLeases/Form.js
+++ b/client/src/components/Settings/Dhcp/StaticLeases/Form.js
@@ -2,7 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Field, reduxForm } from 'redux-form';
 import { Trans, useTranslation } from 'react-i18next';
-import { useDispatch } from 'react-redux';
+import { useDispatch, useSelector, shallowEqual } from 'react-redux';
 
 import { renderInputField, normalizeMac } from '../../../../helpers/form';
 import {
@@ -25,6 +25,7 @@ const Form = ({
 }) => {
     const { t } = useTranslation();
     const dispatch = useDispatch();
+    const dynamicLease = useSelector((store) => store.dhcp.leaseModalConfig, shallowEqual);
 
     const onClick = () => {
         reset();
@@ -87,7 +88,7 @@ const Form = ({
                     <button
                         type="submit"
                         className="btn btn-success btn-standard"
-                        disabled={submitting || pristine || processingAdding}
+                        disabled={submitting || processingAdding || (pristine && !dynamicLease)}
                     >
                         <Trans>save_btn</Trans>
                     </button>
diff --git a/client/src/components/Settings/Dhcp/StaticLeases/Modal.js b/client/src/components/Settings/Dhcp/StaticLeases/Modal.js
index 0baf487e..7a11cfce 100644
--- a/client/src/components/Settings/Dhcp/StaticLeases/Modal.js
+++ b/client/src/components/Settings/Dhcp/StaticLeases/Modal.js
@@ -2,7 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Trans, withTranslation } from 'react-i18next';
 import ReactModal from 'react-modal';
-import { useDispatch } from 'react-redux';
+import { shallowEqual, useDispatch, useSelector } from 'react-redux';
 import Form from './Form';
 import { toggleLeaseModal } from '../../../../actions';
 
@@ -18,6 +18,9 @@ const Modal = ({
     const dispatch = useDispatch();
 
     const toggleModal = () => dispatch(toggleLeaseModal());
+    const leaseInitialData = useSelector(
+        (state) => state.dhcp.leaseModalConfig, shallowEqual,
+    ) || {};
 
     return (
         <ReactModal
@@ -37,9 +40,9 @@ const Modal = ({
                 </div>
                 <Form
                     initialValues={{
-                        mac: '',
-                        ip: '',
-                        hostname: '',
+                        mac: leaseInitialData.mac ?? '',
+                        ip: leaseInitialData.ip ?? '',
+                        hostname: leaseInitialData.hostname ?? '',
                         cidr,
                         rangeStart,
                         rangeEnd,
diff --git a/client/src/components/Settings/Dhcp/StaticLeases/index.js b/client/src/components/Settings/Dhcp/StaticLeases/index.js
index 299d0a7d..849ca664 100644
--- a/client/src/components/Settings/Dhcp/StaticLeases/index.js
+++ b/client/src/components/Settings/Dhcp/StaticLeases/index.js
@@ -54,7 +54,7 @@ const StaticLeases = ({
                     {
                         Header: 'MAC',
                         accessor: 'mac',
-                        minWidth: 160,
+                        minWidth: 180,
                         Cell: cellWrap,
                     },
                     {
diff --git a/client/src/components/Settings/Dhcp/index.js b/client/src/components/Settings/Dhcp/index.js
index bd3a45e3..a509ac49 100644
--- a/client/src/components/Settings/Dhcp/index.js
+++ b/client/src/components/Settings/Dhcp/index.js
@@ -188,8 +188,8 @@ const Dhcp = () => {
 
     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 disabledLeasesButton = Boolean(dhcp?.syncErrors || interfaces?.syncErrors
+        || !isInterfaceIncludesIpv4 || isEmptyConfig || processingConfig || !inputtedIPv4values);
     const cidr = inputtedIPv4values ? `${dhcp?.values?.v4?.gateway_ip}/${subnetMaskToBitMask(dhcp?.values?.v4?.subnet_mask)}` : '';
 
     return <>
@@ -260,7 +260,7 @@ const Dhcp = () => {
             >
                 <div className="row">
                     <div className="col">
-                        <Leases leases={leases} />
+                        <Leases leases={leases} disabledLeasesButton={disabledLeasesButton}/>
                     </div>
                 </div>
             </Card>}
diff --git a/client/src/reducers/dhcp.js b/client/src/reducers/dhcp.js
index 4c2fe991..c0d6e8c0 100644
--- a/client/src/reducers/dhcp.js
+++ b/client/src/reducers/dhcp.js
@@ -124,10 +124,11 @@ const dhcp = handleActions(
             staticLeases: [],
         }),
 
-        [actions.toggleLeaseModal]: (state) => {
+        [actions.toggleLeaseModal]: (state, { payload }) => {
             const newState = {
                 ...state,
                 isModalOpen: !state.isModalOpen,
+                leaseModalConfig: payload,
             };
             return newState;
         },
@@ -200,6 +201,7 @@ const dhcp = handleActions(
         leases: [],
         staticLeases: [],
         isModalOpen: false,
+        leaseModalConfig: undefined,
         dhcp_available: false,
     },
 );