Added initial layout for DHCP server config
This commit is contained in:
committed by
Eugene Bujak
parent
390883126c
commit
dd21f497e3
134
client/src/components/Settings/Dhcp/Form.js
Normal file
134
client/src/components/Settings/Dhcp/Form.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import { R_IPV4 } from '../../../helpers/constants';
|
||||
|
||||
const required = (value) => {
|
||||
if (value) {
|
||||
return false;
|
||||
}
|
||||
return 'Required field';
|
||||
};
|
||||
|
||||
const ipv4 = (value) => {
|
||||
if (value && !new RegExp(R_IPV4).test(value)) {
|
||||
return 'Invalid IPv4 format';
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const renderField = ({
|
||||
input, className, placeholder, type, disabled, meta: { touched, error },
|
||||
}) => (
|
||||
<Fragment>
|
||||
<input
|
||||
{...input}
|
||||
placeholder={placeholder}
|
||||
type={type}
|
||||
className={className}
|
||||
disabled={disabled}
|
||||
/>
|
||||
{!disabled && touched && (error && <span className="form__message form__message--error">{error}</span>)}
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
const Form = (props) => {
|
||||
const {
|
||||
handleSubmit, pristine, submitting, enabled,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="row">
|
||||
<div className="col-lg-6">
|
||||
<div className="form__group form__group--dhcp">
|
||||
<label>Gateway IP</label>
|
||||
<Field
|
||||
name="gateway_ip"
|
||||
component={renderField}
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="Gateway IP"
|
||||
validate={[ipv4, required]}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
</div>
|
||||
<div className="form__group form__group--dhcp">
|
||||
<label>Subnet mask</label>
|
||||
<Field
|
||||
name="subnet_mask"
|
||||
component={renderField}
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="Subnet mask"
|
||||
validate={[ipv4, required]}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<div className="form__group form__group--dhcp">
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<label>Range of IP addresses</label>
|
||||
</div>
|
||||
<div className="col">
|
||||
<Field
|
||||
name="range_start"
|
||||
component={renderField}
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="Range start"
|
||||
validate={[ipv4, required]}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
</div>
|
||||
<div className="col">
|
||||
<Field
|
||||
name="range_end"
|
||||
component={renderField}
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="Range end"
|
||||
validate={[ipv4, required]}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form__group form__group--dhcp">
|
||||
<label>DHCP lease time (in seconds)</label>
|
||||
<Field
|
||||
name="lease_duration"
|
||||
component={renderField}
|
||||
type="number"
|
||||
className="form-control"
|
||||
placeholder="Lease duration"
|
||||
validate={[required]}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-success btn-standart"
|
||||
disabled={pristine || submitting || !enabled}
|
||||
>
|
||||
Save config
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
Form.propTypes = {
|
||||
handleSubmit: PropTypes.func,
|
||||
pristine: PropTypes.bool,
|
||||
submitting: PropTypes.bool,
|
||||
enabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default reduxForm({
|
||||
form: 'dhcpForm',
|
||||
})(Form);
|
||||
36
client/src/components/Settings/Dhcp/Leases.js
Normal file
36
client/src/components/Settings/Dhcp/Leases.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactTable from 'react-table';
|
||||
import { withNamespaces } from 'react-i18next';
|
||||
|
||||
const columns = [{
|
||||
Header: 'MAC',
|
||||
accessor: 'mac',
|
||||
}, {
|
||||
Header: 'IP',
|
||||
accessor: 'ip',
|
||||
}, {
|
||||
Header: 'Hostname',
|
||||
accessor: 'hostname',
|
||||
}, {
|
||||
Header: 'Expires',
|
||||
accessor: 'expires',
|
||||
}];
|
||||
|
||||
const Leases = props => (
|
||||
<ReactTable
|
||||
data={props.leases}
|
||||
columns={columns}
|
||||
showPagination={false}
|
||||
noDataText={ props.t('dhcp_leases_not_found') }
|
||||
minRows={6}
|
||||
className="-striped -highlight card-table-overflow"
|
||||
/>
|
||||
);
|
||||
|
||||
Leases.propTypes = {
|
||||
leases: PropTypes.array,
|
||||
t: PropTypes.func,
|
||||
};
|
||||
|
||||
export default withNamespaces()(Leases);
|
||||
93
client/src/components/Settings/Dhcp/index.js
Normal file
93
client/src/components/Settings/Dhcp/index.js
Normal file
@@ -0,0 +1,93 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { Trans, withNamespaces } from 'react-i18next';
|
||||
|
||||
import Form from './Form';
|
||||
import Leases from './Leases';
|
||||
import Card from '../../ui/Card';
|
||||
|
||||
class Dhcp extends Component {
|
||||
handleFormSubmit = (values) => {
|
||||
this.props.setDhcpConfig(values);
|
||||
};
|
||||
|
||||
handleRefresh = () => {
|
||||
this.props.findActiveDhcp();
|
||||
}
|
||||
|
||||
getToggleDhcpButton = () => {
|
||||
const { enabled } = this.props.dhcp.config;
|
||||
const buttonText = enabled ? 'dhcp_disable' : 'dhcp_enable';
|
||||
const buttonClass = enabled ? 'btn-gray' : 'btn-success';
|
||||
|
||||
return (
|
||||
<button type="button" className={`btn btn-standart mr-2 ${buttonClass}`} onClick={() => this.props.toggleDhcp(enabled)}>
|
||||
<Trans>{buttonText}</Trans>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t, dhcp } = this.props;
|
||||
const statusButtonClass = classnames({
|
||||
'btn btn-primary btn-standart': true,
|
||||
'btn btn-primary btn-standart btn-loading': dhcp.processingStatus,
|
||||
});
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{!dhcp.processing &&
|
||||
<Card title={ t('dhcp_title') } subtitle={ t('dhcp_description') } bodyType="card-body box-body--settings">
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<div className="card-actions mt-0 mb-3">
|
||||
{this.getToggleDhcpButton()}
|
||||
<button
|
||||
className={statusButtonClass}
|
||||
type="button"
|
||||
onClick={this.handleRefresh}
|
||||
>
|
||||
<Trans>refresh_status</Trans>
|
||||
</button>
|
||||
</div>
|
||||
{dhcp.active && !dhcp.active.found &&
|
||||
<div className="text-secondary">
|
||||
<Trans>dhcp_not_found</Trans>
|
||||
</div>
|
||||
}
|
||||
<hr/>
|
||||
<Form
|
||||
onSubmit={this.handleFormSubmit}
|
||||
initialValues={dhcp.config}
|
||||
enabled={dhcp.config.enabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
}
|
||||
{!dhcp.processing && dhcp.config.enabled &&
|
||||
<Card title={ t('dhcp_leases') } bodyType="card-body box-body--settings">
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<Leases leases={dhcp.leases} />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Dhcp.propTypes = {
|
||||
dhcp: PropTypes.object,
|
||||
toggleDhcp: PropTypes.func,
|
||||
getDhcpStatus: PropTypes.func,
|
||||
setDhcpConfig: PropTypes.func,
|
||||
findActiveDhcp: PropTypes.func,
|
||||
handleSubmit: PropTypes.func,
|
||||
t: PropTypes.func,
|
||||
};
|
||||
|
||||
export default withNamespaces()(Dhcp);
|
||||
@@ -1,4 +1,5 @@
|
||||
.form__group {
|
||||
position: relative;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
@@ -6,6 +7,10 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form__group--dhcp:last-child {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.btn-standart {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
@@ -18,3 +23,11 @@
|
||||
.form-control--textarea-large {
|
||||
min-height: 240px;
|
||||
}
|
||||
|
||||
.form__message {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.form__message--error {
|
||||
color: #cd201f;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withNamespaces, Trans } from 'react-i18next';
|
||||
import Upstream from './Upstream';
|
||||
import Dhcp from './Dhcp';
|
||||
import Checkbox from '../ui/Checkbox';
|
||||
import Loading from '../ui/Loading';
|
||||
import PageTitle from '../ui/PageTitle';
|
||||
@@ -34,6 +35,7 @@ class Settings extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.initSettings(this.settings);
|
||||
this.props.getDhcpStatus();
|
||||
}
|
||||
|
||||
handleUpstreamChange = (value) => {
|
||||
@@ -92,6 +94,13 @@ class Settings extends Component {
|
||||
handleUpstreamSubmit={this.handleUpstreamSubmit}
|
||||
handleUpstreamTest={this.handleUpstreamTest}
|
||||
/>
|
||||
<Dhcp
|
||||
dhcp={this.props.dhcp}
|
||||
toggleDhcp={this.props.toggleDhcp}
|
||||
getDhcpStatus={this.props.getDhcpStatus}
|
||||
findActiveDhcp={this.props.findActiveDhcp}
|
||||
setDhcpConfig={this.props.setDhcpConfig}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user