diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 9ff11424..6b0bc715 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -17,7 +17,7 @@ "dhcp_leases": "DHCP leases", "dhcp_static_leases": "DHCP static leases", "dhcp_leases_not_found": "No DHCP leases found", - "dhcp_config_saved": "Saved DHCP server config", + "dhcp_config_saved": "DHCP config successfully saved", "form_error_required": "Required field", "form_error_ip4_format": "Invalid IPv4 format", "form_error_ip6_format": "Invalid IPv6 format", @@ -45,6 +45,7 @@ "dhcp_new_static_lease": "New static lease", "dhcp_static_leases_not_found": "No DHCP static leases found", "dhcp_add_static_lease": "Add static lease", + "dhcp_reset": "Are you sure you want to reset DHCP config?", "delete_confirm": "Are you sure you want to delete \"{{key}}\"?", "form_enter_hostname": "Enter hostname", "error_details": "Error details", diff --git a/client/src/actions/index.js b/client/src/actions/index.js index 28c2a713..d01130f6 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -470,6 +470,22 @@ export const toggleDhcp = values => async (dispatch) => { } }; +export const resetDhcpRequest = createAction('RESET_DHCP_REQUEST'); +export const resetDhcpSuccess = createAction('RESET_DHCP_SUCCESS'); +export const resetDhcpFailure = createAction('RESET_DHCP_FAILURE'); + +export const resetDhcp = () => async (dispatch) => { + dispatch(resetDhcpRequest()); + try { + const status = await apiClient.resetDhcp(); + dispatch(resetDhcpSuccess(status)); + dispatch(addSuccessToast('dhcp_config_saved')); + } catch (error) { + dispatch(addErrorToast({ error })); + dispatch(resetDhcpFailure()); + } +}; + export const toggleLeaseModal = createAction('TOGGLE_LEASE_MODAL'); export const addStaticLeaseRequest = createAction('ADD_STATIC_LEASE_REQUEST'); diff --git a/client/src/api/Api.js b/client/src/api/Api.js index 72d6d527..2393a89d 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -248,6 +248,7 @@ class Api { DHCP_INTERFACES = { path: 'dhcp/interfaces', method: 'GET' }; DHCP_ADD_STATIC_LEASE = { path: 'dhcp/add_static_lease', method: 'POST' }; DHCP_REMOVE_STATIC_LEASE = { path: 'dhcp/remove_static_lease', method: 'POST' }; + DHCP_RESET = { path: 'dhcp/reset', method: 'POST' }; getDhcpStatus() { const { path, method } = this.DHCP_STATUS; @@ -295,6 +296,11 @@ class Api { return this.makeRequest(path, method, parameters); } + resetDhcp() { + const { path, method } = this.DHCP_RESET; + return this.makeRequest(path, method); + } + // Installation INSTALL_GET_ADDRESSES = { path: 'install/get_addresses', method: 'GET' }; INSTALL_CONFIGURE = { path: 'install/configure', method: 'POST' }; diff --git a/client/src/components/Settings/Dhcp/Form.js b/client/src/components/Settings/Dhcp/Form.js index 86de6340..8bbef865 100644 --- a/client/src/components/Settings/Dhcp/Form.js +++ b/client/src/components/Settings/Dhcp/Form.js @@ -50,6 +50,23 @@ const renderInterfaceValues = (interfaceValues => ( )); +const clearFields = (change, resetDhcp, t) => { + const fields = { + interface_name: '', + gateway_ip: '', + subnet_mask: '', + range_start: '', + range_end: '', + lease_duration: 86400, + }; + + // eslint-disable-next-line no-alert + if (window.confirm(t('dhcp_reset'))) { + Object.keys(fields).forEach(field => change(field, fields[field])); + resetDhcp(); + } +}; + let Form = (props) => { const { t, @@ -61,6 +78,8 @@ let Form = (props) => { interfaceValue, processingConfig, processingInterfaces, + resetDhcp, + change, } = props; return ( @@ -160,31 +179,42 @@ let Form = (props) => { - +
+ + +
); }; Form.propTypes = { - handleSubmit: PropTypes.func, - submitting: PropTypes.bool, - invalid: PropTypes.bool, - interfaces: PropTypes.object, + handleSubmit: PropTypes.func.isRequired, + submitting: PropTypes.bool.isRequired, + invalid: PropTypes.bool.isRequired, + interfaces: PropTypes.object.isRequired, interfaceValue: PropTypes.string, - initialValues: PropTypes.object, - processingConfig: PropTypes.bool, - processingInterfaces: PropTypes.bool, - enabled: PropTypes.bool, - t: PropTypes.func, + initialValues: PropTypes.object.isRequired, + processingConfig: PropTypes.bool.isRequired, + processingInterfaces: PropTypes.bool.isRequired, + enabled: PropTypes.bool.isRequired, + t: PropTypes.func.isRequired, + resetDhcp: PropTypes.func.isRequired, + change: PropTypes.func.isRequired, }; - const selector = formValueSelector('dhcpForm'); Form = connect((state) => { diff --git a/client/src/components/Settings/Dhcp/index.js b/client/src/components/Settings/Dhcp/index.js index 626c18d4..959922ce 100644 --- a/client/src/components/Settings/Dhcp/index.js +++ b/client/src/components/Settings/Dhcp/index.js @@ -154,7 +154,15 @@ class Dhcp extends Component { }; render() { - const { t, dhcp } = this.props; + const { + t, + dhcp, + resetDhcp, + findActiveDhcp, + addStaticLease, + removeStaticLease, + toggleLeaseModal, + } = this.props; const statusButtonClass = classnames({ 'btn btn-primary btn-standard': true, 'btn btn-primary btn-standard btn-loading': dhcp.processingStatus, @@ -184,6 +192,7 @@ class Dhcp extends Component { processingConfig={dhcp.processingConfig} processingInterfaces={dhcp.processingInterfaces} enabled={enabled} + resetDhcp={resetDhcp} />
@@ -191,9 +200,7 @@ class Dhcp extends Component { @@ -260,16 +267,17 @@ class Dhcp extends Component { } Dhcp.propTypes = { - dhcp: PropTypes.object, - toggleDhcp: PropTypes.func, - getDhcpStatus: PropTypes.func, - setDhcpConfig: PropTypes.func, - findActiveDhcp: PropTypes.func, - addStaticLease: PropTypes.func, - removeStaticLease: PropTypes.func, - toggleLeaseModal: PropTypes.func, - getDhcpInterfaces: PropTypes.func, - t: PropTypes.func, + dhcp: PropTypes.object.isRequired, + toggleDhcp: PropTypes.func.isRequired, + getDhcpStatus: PropTypes.func.isRequired, + setDhcpConfig: PropTypes.func.isRequired, + findActiveDhcp: PropTypes.func.isRequired, + addStaticLease: PropTypes.func.isRequired, + removeStaticLease: PropTypes.func.isRequired, + toggleLeaseModal: PropTypes.func.isRequired, + getDhcpInterfaces: PropTypes.func.isRequired, + t: PropTypes.func.isRequired, + resetDhcp: PropTypes.func.isRequired, }; export default withNamespaces()(Dhcp); diff --git a/client/src/containers/Dhcp.js b/client/src/containers/Dhcp.js index 6f2b8f47..1f9d6b62 100644 --- a/client/src/containers/Dhcp.js +++ b/client/src/containers/Dhcp.js @@ -8,6 +8,7 @@ import { toggleLeaseModal, addStaticLease, removeStaticLease, + resetDhcp, } from '../actions'; import Dhcp from '../components/Settings/Dhcp'; @@ -28,6 +29,7 @@ const mapDispatchToProps = { toggleLeaseModal, addStaticLease, removeStaticLease, + resetDhcp, }; export default connect( diff --git a/client/src/reducers/index.js b/client/src/reducers/index.js index 0e8ff407..3eca36a6 100644 --- a/client/src/reducers/index.js +++ b/client/src/reducers/index.js @@ -289,6 +289,16 @@ const dhcp = handleActions( return newState; }, + [actions.resetDhcpRequest]: state => ({ ...state, processingReset: true }), + [actions.resetDhcpFailure]: state => ({ ...state, processingReset: false }), + [actions.resetDhcpSuccess]: state => ({ + ...state, + processingReset: false, + config: { + enabled: false, + }, + }), + [actions.toggleLeaseModal]: (state) => { const newState = { ...state,