Merge: DHCP: check/set static IP
Close #686 * commit '828d3121be807daa8f839dfa7a7ac4ba8a6e7cd8': * client: show message if there is no static ip * client: rename constant * hasStaticIP: use properly named boolean variable + client: static_ip warnings * client: error text * client: disable DHCP check if server enabled and hide errors on disable * client: hide error if DHCP enabled and require check DHCP before enabling * client: accordion styles - client: fix DHCP fields validation * client: fix DHCP error message + config: set default parameters for DHCP server + /control/dhcp/set_config: set static IP + /control/dhcp/find_active_dhcp: detect static IP on Linux * /control/dhcp/find_active_dhcp: new JSON response format
This commit is contained in:
@@ -32,7 +32,11 @@
|
||||
"dhcp_ip_addresses": "IP addresses",
|
||||
"dhcp_table_hostname": "Hostname",
|
||||
"dhcp_table_expires": "Expires",
|
||||
"dhcp_warning": "If you want to enable the built-in DHCP server, make sure that there is no other active DHCP server. Otherwise, it can break the internet for connected devices!",
|
||||
"dhcp_warning": "If you want to enable DHCP server anyway, make sure that there is no other active DHCP server in your network. Otherwise, it can break the Internet for connected devices!",
|
||||
"dhcp_error": "We could not determine whether there is another DHCP server in the network.",
|
||||
"dhcp_static_ip_error": "In order to use DHCP server a static IP address must be set. We failed to determine if this network interface is configured using static IP address. Please set a static IP address manually.",
|
||||
"dhcp_dynamic_ip_found": "Your system uses dynamic IP address configuration for interface <0>{{interfaceName}}</0>. In order to use DHCP server a static IP address must be set. Your current IP address is <0>{{ipAddress}}</0>. We will automatically set this IP address as static if you press Enable DHCP button.",
|
||||
"error_details": "Error details",
|
||||
"back": "Back",
|
||||
"dashboard": "Dashboard",
|
||||
"settings": "Settings",
|
||||
|
||||
@@ -3,10 +3,12 @@ import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { Trans, withNamespaces } from 'react-i18next';
|
||||
|
||||
import { DHCP_STATUS_RESPONSE } from '../../../helpers/constants';
|
||||
import Form from './Form';
|
||||
import Leases from './Leases';
|
||||
import Interface from './Interface';
|
||||
import Card from '../../ui/Card';
|
||||
import Accordion from '../../ui/Accordion';
|
||||
|
||||
class Dhcp extends Component {
|
||||
handleFormSubmit = (values) => {
|
||||
@@ -19,11 +21,12 @@ class Dhcp extends Component {
|
||||
|
||||
getToggleDhcpButton = () => {
|
||||
const {
|
||||
config, active, processingDhcp, processingConfig,
|
||||
config, check, processingDhcp, processingConfig,
|
||||
} = this.props.dhcp;
|
||||
const activeDhcpFound = active && active.found;
|
||||
const otherDhcpFound =
|
||||
check && check.otherServer && check.otherServer.found === DHCP_STATUS_RESPONSE.YES;
|
||||
const filledConfig = Object.keys(config).every((key) => {
|
||||
if (key === 'enabled') {
|
||||
if (key === 'enabled' || key === 'icmp_timeout_msec') {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -50,7 +53,8 @@ class Dhcp extends Component {
|
||||
onClick={() => this.handleToggle(config)}
|
||||
disabled={
|
||||
!filledConfig
|
||||
|| activeDhcpFound
|
||||
|| !check
|
||||
|| otherDhcpFound
|
||||
|| processingDhcp
|
||||
|| processingConfig
|
||||
}
|
||||
@@ -60,33 +64,89 @@ class Dhcp extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
getActiveDhcpMessage = () => {
|
||||
const { active } = this.props.dhcp;
|
||||
|
||||
if (active) {
|
||||
if (active.error) {
|
||||
return (
|
||||
<div className="text-danger mb-2">
|
||||
{active.error}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
getActiveDhcpMessage = (t, check) => {
|
||||
const { found } = check.otherServer;
|
||||
|
||||
if (found === DHCP_STATUS_RESPONSE.ERROR) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
{active.found ? (
|
||||
<div className="text-danger">
|
||||
<Trans>dhcp_found</Trans>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-secondary">
|
||||
<Trans>dhcp_not_found</Trans>
|
||||
</div>
|
||||
)}
|
||||
<div className="text-danger mb-2">
|
||||
<Trans>dhcp_error</Trans>
|
||||
<div className="mt-2 mb-2">
|
||||
<Accordion label={t('error_details')}>
|
||||
<span>{check.otherServer.error}</span>
|
||||
</Accordion>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mb-2">
|
||||
{found === DHCP_STATUS_RESPONSE.YES ? (
|
||||
<div className="text-danger">
|
||||
<Trans>dhcp_found</Trans>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-secondary">
|
||||
<Trans>dhcp_not_found</Trans>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
getDhcpWarning = (check) => {
|
||||
if (check.otherServer.found === DHCP_STATUS_RESPONSE.NO) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-danger">
|
||||
<Trans>dhcp_warning</Trans>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
getStaticIpWarning = (t, check, interfaceName) => {
|
||||
if (check.staticIP.static === DHCP_STATUS_RESPONSE.ERROR) {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="text-danger mb-2">
|
||||
<Trans>dhcp_static_ip_error</Trans>
|
||||
<div className="mt-2 mb-2">
|
||||
<Accordion label={t('error_details')}>
|
||||
<span>{check.staticIP.error}</span>
|
||||
</Accordion>
|
||||
</div>
|
||||
</div>
|
||||
<hr className="mt-4 mb-4"/>
|
||||
</Fragment>
|
||||
);
|
||||
} else if (
|
||||
check.staticIP.static === DHCP_STATUS_RESPONSE.NO
|
||||
&& check.staticIP.ip
|
||||
&& interfaceName
|
||||
) {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="text-secondary mb-2">
|
||||
<Trans
|
||||
components={[
|
||||
<strong key="0">example</strong>,
|
||||
]}
|
||||
values={{
|
||||
interfaceName,
|
||||
ipAddress: check.staticIP.ip,
|
||||
}}
|
||||
>
|
||||
dhcp_dynamic_ip_found
|
||||
</Trans>
|
||||
</div>
|
||||
<hr className="mt-4 mb-4"/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -131,17 +191,21 @@ class Dhcp extends Component {
|
||||
this.props.findActiveDhcp(dhcp.config.interface_name)
|
||||
}
|
||||
disabled={
|
||||
!dhcp.config.interface_name
|
||||
dhcp.config.enabled
|
||||
|| !dhcp.config.interface_name
|
||||
|| dhcp.processingConfig
|
||||
}
|
||||
>
|
||||
<Trans>check_dhcp_servers</Trans>
|
||||
</button>
|
||||
</div>
|
||||
{this.getActiveDhcpMessage()}
|
||||
<div className="text-danger">
|
||||
<Trans>dhcp_warning</Trans>
|
||||
</div>
|
||||
{!enabled && dhcp.check &&
|
||||
<Fragment>
|
||||
{this.getStaticIpWarning(t, dhcp.check, interface_name)}
|
||||
{this.getActiveDhcpMessage(t, dhcp.check)}
|
||||
{this.getDhcpWarning(dhcp.check)}
|
||||
</Fragment>
|
||||
}
|
||||
</Fragment>
|
||||
}
|
||||
</div>
|
||||
|
||||
32
client/src/components/ui/Accordion.css
Normal file
32
client/src/components/ui/Accordion.css
Normal file
@@ -0,0 +1,32 @@
|
||||
.accordion {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.accordion__label {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding-left: 25px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.accordion__label:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 0;
|
||||
width: 17px;
|
||||
height: 10px;
|
||||
background-image: url("./svg/chevron-down.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.accordion__label--open:after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.accordion__content {
|
||||
padding-top: 5px;
|
||||
}
|
||||
43
client/src/components/ui/Accordion.js
Normal file
43
client/src/components/ui/Accordion.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import './Accordion.css';
|
||||
|
||||
class Accordion extends Component {
|
||||
state = {
|
||||
isOpen: false,
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
this.setState(prevState => ({ isOpen: !prevState.isOpen }));
|
||||
};
|
||||
|
||||
render() {
|
||||
const accordionClass = this.state.isOpen
|
||||
? 'accordion__label accordion__label--open'
|
||||
: 'accordion__label';
|
||||
|
||||
return (
|
||||
<div className="accordion">
|
||||
<div
|
||||
className={accordionClass}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{this.props.label}
|
||||
</div>
|
||||
{this.state.isOpen && (
|
||||
<div className="accordion__content">
|
||||
{this.props.children}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Accordion.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Accordion;
|
||||
@@ -157,3 +157,9 @@ export const UNSAFE_PORTS = [
|
||||
];
|
||||
|
||||
export const ALL_INTERFACES_IP = '0.0.0.0';
|
||||
|
||||
export const DHCP_STATUS_RESPONSE = {
|
||||
YES: 'yes',
|
||||
NO: 'no',
|
||||
ERROR: 'error',
|
||||
};
|
||||
|
||||
@@ -292,18 +292,31 @@ const dhcp = handleActions({
|
||||
|
||||
[actions.findActiveDhcpRequest]: state => ({ ...state, processingStatus: true }),
|
||||
[actions.findActiveDhcpFailure]: state => ({ ...state, processingStatus: false }),
|
||||
[actions.findActiveDhcpSuccess]: (state, { payload }) => ({
|
||||
...state,
|
||||
active: payload,
|
||||
processingStatus: false,
|
||||
}),
|
||||
[actions.findActiveDhcpSuccess]: (state, { payload }) => {
|
||||
const {
|
||||
other_server: otherServer,
|
||||
static_ip: staticIP,
|
||||
} = payload;
|
||||
|
||||
const newState = {
|
||||
...state,
|
||||
check: {
|
||||
otherServer,
|
||||
staticIP,
|
||||
},
|
||||
processingStatus: false,
|
||||
};
|
||||
return newState;
|
||||
},
|
||||
|
||||
[actions.toggleDhcpRequest]: state => ({ ...state, processingDhcp: true }),
|
||||
[actions.toggleDhcpFailure]: state => ({ ...state, processingDhcp: false }),
|
||||
[actions.toggleDhcpSuccess]: (state) => {
|
||||
const { config } = state;
|
||||
const newConfig = { ...config, enabled: !config.enabled };
|
||||
const newState = { ...state, config: newConfig, processingDhcp: false };
|
||||
const newState = {
|
||||
...state, config: newConfig, check: null, processingDhcp: false,
|
||||
};
|
||||
return newState;
|
||||
},
|
||||
|
||||
@@ -324,7 +337,7 @@ const dhcp = handleActions({
|
||||
config: {
|
||||
enabled: false,
|
||||
},
|
||||
active: null,
|
||||
check: null,
|
||||
leases: [],
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user