Merge: - client: fix upstream DNS servers form

* commit '59a635f3f23bfcca583960f8ebb910d35f13e34d':
  + client: add isVersionGreater helper
  - client: fix upstream DNS servers form
This commit is contained in:
Ildar Kamalov 2019-09-17 18:27:49 +03:00
commit 74381b0cad
9 changed files with 368 additions and 300 deletions

View file

@ -2,8 +2,7 @@ import { createAction } from 'redux-actions';
import { t } from 'i18next'; import { t } from 'i18next';
import axios from 'axios'; import axios from 'axios';
import versionCompare from '../helpers/versionCompare'; import { normalizeTextarea, sortClients, isVersionGreater } from '../helpers/helpers';
import { normalizeTextarea, sortClients } from '../helpers/helpers';
import { SETTINGS_NAMES, CHECK_TIMEOUT } from '../helpers/constants'; import { SETTINGS_NAMES, CHECK_TIMEOUT } from '../helpers/constants';
import { getTlsStatus } from './encryption'; import { getTlsStatus } from './encryption';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
@ -125,7 +124,7 @@ export const getVersion = (recheck = false) => async (dispatch, getState) => {
const { dnsVersion } = getState().dashboard; const { dnsVersion } = getState().dashboard;
const currentVersion = dnsVersion === 'undefined' ? 0 : dnsVersion; const currentVersion = dnsVersion === 'undefined' ? 0 : dnsVersion;
if (data && versionCompare(currentVersion, data.new_version) === -1) { if (data && isVersionGreater(currentVersion, data.new_version)) {
dispatch(addSuccessToast('updates_checked')); dispatch(addSuccessToast('updates_checked'));
} else { } else {
dispatch(addSuccessToast('updates_version_equal')); dispatch(addSuccessToast('updates_version_equal'));
@ -227,7 +226,22 @@ export const getDnsStatus = () => async (dispatch) => {
dispatch(getTlsStatus()); dispatch(getTlsStatus());
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));
dispatch(initSettingsFailure()); dispatch(dnsStatusFailure());
}
};
export const getDnsSettingsRequest = createAction('GET_DNS_SETTINGS_REQUEST');
export const getDnsSettingsFailure = createAction('GET_DNS_SETTINGS_FAILURE');
export const getDnsSettingsSuccess = createAction('GET_DNS_SETTINGS_SUCCESS');
export const getDnsSettings = () => async (dispatch) => {
dispatch(getDnsSettingsRequest());
try {
const dnsStatus = await apiClient.getGlobalStatus();
dispatch(getDnsSettingsSuccess(dnsStatus));
} catch (error) {
dispatch(addErrorToast({ error }));
dispatch(getDnsSettingsFailure());
} }
}; };
@ -279,7 +293,7 @@ export const setUpstream = config => async (dispatch) => {
await apiClient.setUpstream(values); await apiClient.setUpstream(values);
dispatch(addSuccessToast('updated_upstream_dns_toast')); dispatch(addSuccessToast('updated_upstream_dns_toast'));
dispatch(setUpstreamSuccess()); dispatch(setUpstreamSuccess(config));
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));
dispatch(setUpstreamFailure()); dispatch(setUpstreamFailure());

View file

@ -5,7 +5,9 @@ import { Trans, withNamespaces } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
const Form = (props) => { const Form = (props) => {
const { handleSubmit, submitting, invalid } = props; const {
handleSubmit, submitting, invalid, processingSet,
} = props;
return ( return (
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
@ -22,6 +24,7 @@ const Form = (props) => {
component="textarea" component="textarea"
type="text" type="text"
className="form-control form-control--textarea" className="form-control form-control--textarea"
disabled={processingSet}
/> />
</div> </div>
<div className="form__group mb-5"> <div className="form__group mb-5">
@ -37,6 +40,7 @@ const Form = (props) => {
component="textarea" component="textarea"
type="text" type="text"
className="form-control form-control--textarea" className="form-control form-control--textarea"
disabled={processingSet}
/> />
</div> </div>
<div className="form__group mb-5"> <div className="form__group mb-5">
@ -52,6 +56,7 @@ const Form = (props) => {
component="textarea" component="textarea"
type="text" type="text"
className="form-control form-control--textarea" className="form-control form-control--textarea"
disabled={processingSet}
/> />
</div> </div>
<div className="card-actions"> <div className="card-actions">
@ -59,7 +64,7 @@ const Form = (props) => {
<button <button
type="submit" type="submit"
className="btn btn-success btn-standard" className="btn btn-success btn-standard"
disabled={submitting || invalid} disabled={submitting || invalid || processingSet}
> >
<Trans>save_config</Trans> <Trans>save_config</Trans>
</button> </button>
@ -70,11 +75,12 @@ const Form = (props) => {
}; };
Form.propTypes = { Form.propTypes = {
handleSubmit: PropTypes.func, handleSubmit: PropTypes.func.isRequired,
submitting: PropTypes.bool, submitting: PropTypes.bool.isRequired,
invalid: PropTypes.bool, invalid: PropTypes.bool.isRequired,
initialValues: PropTypes.object, initialValues: PropTypes.object.isRequired,
t: PropTypes.func, processingSet: PropTypes.bool.isRequired,
t: PropTypes.func.isRequired,
}; };
export default flow([withNamespaces(), reduxForm({ form: 'accessForm' })])(Form); export default flow([withNamespaces(), reduxForm({ form: 'accessForm' })])(Form);

View file

@ -13,11 +13,7 @@ class Access extends Component {
render() { render() {
const { t, access } = this.props; const { t, access } = this.props;
const { const { processing, processingSet, ...values } = access;
processing,
processingSet,
...values
} = access;
return ( return (
<Card <Card
@ -28,6 +24,7 @@ class Access extends Component {
<Form <Form
initialValues={values} initialValues={values}
onSubmit={this.handleFormSubmit} onSubmit={this.handleFormSubmit}
processingSet={processingSet}
/> />
</Card> </Card>
); );

View file

@ -43,6 +43,7 @@ let Form = (props) => {
type="text" type="text"
className="form-control form-control--textarea" className="form-control form-control--textarea"
placeholder={t('upstream_dns')} placeholder={t('upstream_dns')}
disabled={processingSetUpstream || processingTestUpstream}
/> />
</div> </div>
</div> </div>
@ -53,6 +54,7 @@ let Form = (props) => {
type="checkbox" type="checkbox"
component={renderSelectField} component={renderSelectField}
placeholder={t('upstream_parallel')} placeholder={t('upstream_parallel')}
disabled={processingSetUpstream}
/> />
</div> </div>
</div> </div>
@ -62,7 +64,10 @@ let Form = (props) => {
</div> </div>
<div className="col-12"> <div className="col-12">
<div className="form__group"> <div className="form__group">
<label className="form__label form__label--with-desc" htmlFor="bootstrap_dns"> <label
className="form__label form__label--with-desc"
htmlFor="bootstrap_dns"
>
<Trans>bootstrap_dns</Trans> <Trans>bootstrap_dns</Trans>
</label> </label>
<div className="form__desc form__desc--top"> <div className="form__desc form__desc--top">
@ -73,8 +78,9 @@ let Form = (props) => {
name="bootstrap_dns" name="bootstrap_dns"
component="textarea" component="textarea"
type="text" type="text"
className="form-control" className="form-control form-control--textarea form-control--textarea-small"
placeholder={t('bootstrap_dns')} placeholder={t('bootstrap_dns')}
disabled={processingSetUpstream}
/> />
</div> </div>
</div> </div>

View file

@ -10,6 +10,7 @@ import Loading from '../../ui/Loading';
class Dns extends Component { class Dns extends Component {
componentDidMount() { componentDidMount() {
this.props.getDnsSettings();
this.props.getAccessList(); this.props.getAccessList();
this.props.getRewritesList(); this.props.getRewritesList();
} }
@ -30,11 +31,16 @@ class Dns extends Component {
toggleRewritesModal, toggleRewritesModal,
} = this.props; } = this.props;
const isDataLoading =
dashboard.processingDnsSettings || access.processing || rewrites.processing;
const isDataReady =
!dashboard.processingDnsSettings && !access.processing && !rewrites.processing;
return ( return (
<Fragment> <Fragment>
<PageTitle title={t('dns_settings')} /> <PageTitle title={t('dns_settings')} />
{(dashboard.processing || access.processing) && <Loading />} {isDataLoading && <Loading />}
{!dashboard.processing && !access.processing && ( {isDataReady && (
<Fragment> <Fragment>
<Upstream <Upstream
upstreamDns={dashboard.upstreamDns} upstreamDns={dashboard.upstreamDns}
@ -73,6 +79,7 @@ Dns.propTypes = {
addRewrite: PropTypes.func.isRequired, addRewrite: PropTypes.func.isRequired,
deleteRewrite: PropTypes.func.isRequired, deleteRewrite: PropTypes.func.isRequired,
toggleRewritesModal: PropTypes.func.isRequired, toggleRewritesModal: PropTypes.func.isRequired,
getDnsSettings: PropTypes.func.isRequired,
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };

View file

@ -38,6 +38,11 @@
.form-control--textarea { .form-control--textarea {
min-height: 110px; min-height: 110px;
transition: 0.3s ease-in-out background-color;
}
.form-control--textarea-small {
min-height: 90px;
} }
.form-control--textarea-large { .form-control--textarea-large {

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { handleUpstreamChange, setUpstream, testUpstream } from '../actions'; import { handleUpstreamChange, setUpstream, testUpstream, getDnsSettings } from '../actions';
import { getAccessList, setAccessList } from '../actions/access'; import { getAccessList, setAccessList } from '../actions/access';
import { import {
getRewritesList, getRewritesList,
@ -32,6 +32,7 @@ const mapDispatchToProps = {
addRewrite, addRewrite,
deleteRewrite, deleteRewrite,
toggleRewritesModal, toggleRewritesModal,
getDnsSettings,
}; };
export default connect( export default connect(

View file

@ -7,6 +7,7 @@ import subDays from 'date-fns/sub_days';
import round from 'lodash/round'; import round from 'lodash/round';
import axios from 'axios'; import axios from 'axios';
import i18n from 'i18next'; import i18n from 'i18next';
import versionCompare from './versionCompare';
import { import {
STANDARD_DNS_PORT, STANDARD_DNS_PORT,
@ -279,3 +280,7 @@ export const secondsToMilliseconds = (seconds) => {
}; };
export const normalizeRulesTextarea = text => text && text.replace(/^\n/g, '').replace(/\n\s*\n/g, '\n'); export const normalizeRulesTextarea = text => text && text.replace(/^\n/g, '').replace(/\n\s*\n/g, '\n');
export const isVersionGreater = (currentVersion, previousVersion) => (
versionCompare(currentVersion, previousVersion) === -1
);

View file

@ -2,7 +2,7 @@ import { combineReducers } from 'redux';
import { handleActions } from 'redux-actions'; import { handleActions } from 'redux-actions';
import { loadingBarReducer } from 'react-redux-loading-bar'; import { loadingBarReducer } from 'react-redux-loading-bar';
import { reducer as formReducer } from 'redux-form'; import { reducer as formReducer } from 'redux-form';
import versionCompare from '../helpers/versionCompare'; import { isVersionGreater } from '../helpers/helpers';
import * as actions from '../actions'; import * as actions from '../actions';
import toasts from './toasts'; import toasts from './toasts';
@ -15,7 +15,8 @@ import stats from './stats';
import queryLogs from './queryLogs'; import queryLogs from './queryLogs';
import filtering from './filtering'; import filtering from './filtering';
const settings = handleActions({ const settings = handleActions(
{
[actions.initSettingsRequest]: state => ({ ...state, processing: true }), [actions.initSettingsRequest]: state => ({ ...state, processing: true }),
[actions.initSettingsFailure]: state => ({ ...state, processing: false }), [actions.initSettingsFailure]: state => ({ ...state, processing: false }),
[actions.initSettingsSuccess]: (state, { payload }) => { [actions.initSettingsSuccess]: (state, { payload }) => {
@ -33,22 +34,29 @@ const settings = handleActions({
const newSettingsList = { ...settingsList, [settingKey]: newSetting }; const newSettingsList = { ...settingsList, [settingKey]: newSetting };
return { ...state, settingsList: newSettingsList }; return { ...state, settingsList: newSettingsList };
}, },
[actions.setUpstreamRequest]: state => ({ ...state, processingUpstream: true }), [actions.setUpstreamRequest]: state => ({ ...state, processingSetUpstream: true }),
[actions.setUpstreamFailure]: state => ({ ...state, processingUpstream: false }), [actions.setUpstreamFailure]: state => ({ ...state, processingSetUpstream: false }),
[actions.setUpstreamSuccess]: state => ({ ...state, processingUpstream: false }), [actions.setUpstreamSuccess]: (state, { payload }) => ({
...state,
...payload,
processingSetUpstream: false,
}),
[actions.testUpstreamRequest]: state => ({ ...state, processingTestUpstream: true }), [actions.testUpstreamRequest]: state => ({ ...state, processingTestUpstream: true }),
[actions.testUpstreamFailure]: state => ({ ...state, processingTestUpstream: false }), [actions.testUpstreamFailure]: state => ({ ...state, processingTestUpstream: false }),
[actions.testUpstreamSuccess]: state => ({ ...state, processingTestUpstream: false }), [actions.testUpstreamSuccess]: state => ({ ...state, processingTestUpstream: false }),
}, { },
{
processing: true, processing: true,
processingTestUpstream: false, processingTestUpstream: false,
processingSetUpstream: false, processingSetUpstream: false,
processingDhcpStatus: false, processingDhcpStatus: false,
settingsList: {}, settingsList: {},
}); },
);
const dashboard = handleActions({ const dashboard = handleActions(
{
[actions.dnsStatusRequest]: state => ({ ...state, processing: true }), [actions.dnsStatusRequest]: state => ({ ...state, processing: true }),
[actions.dnsStatusFailure]: state => ({ ...state, processing: false }), [actions.dnsStatusFailure]: state => ({ ...state, processing: false }),
[actions.dnsStatusSuccess]: (state, { payload }) => { [actions.dnsStatusSuccess]: (state, { payload }) => {
@ -100,7 +108,7 @@ const dashboard = handleActions({
[actions.getVersionSuccess]: (state, { payload }) => { [actions.getVersionSuccess]: (state, { payload }) => {
const currentVersion = state.dnsVersion === 'undefined' ? 0 : state.dnsVersion; const currentVersion = state.dnsVersion === 'undefined' ? 0 : state.dnsVersion;
if (payload && versionCompare(currentVersion, payload.new_version) === -1) { if (payload && isVersionGreater(currentVersion, payload.new_version)) {
const { const {
announcement_url: announcementUrl, announcement_url: announcementUrl,
new_version: newVersion, new_version: newVersion,
@ -163,13 +171,33 @@ const dashboard = handleActions({
}; };
return newState; return newState;
}, },
}, {
[actions.getDnsSettingsRequest]: state => ({ ...state, processingDnsSettings: true }),
[actions.getDnsSettingsFailure]: state => ({ ...state, processingDnsSettings: false }),
[actions.getDnsSettingsSuccess]: (state, { payload }) => {
const {
upstream_dns: upstreamDns,
bootstrap_dns: bootstrapDns,
all_servers: allServers,
} = payload;
return {
...state,
allServers,
upstreamDns: (upstreamDns && upstreamDns.join('\n')) || '',
bootstrapDns: (bootstrapDns && bootstrapDns.join('\n')) || '',
processingDnsSettings: false,
};
},
},
{
processing: true, processing: true,
isCoreRunning: false, isCoreRunning: false,
processingVersion: true, processingVersion: true,
processingFiltering: true, processingFiltering: true,
processingClients: true, processingClients: true,
processingUpdate: false, processingUpdate: false,
processingDnsSettings: true,
upstreamDns: '', upstreamDns: '',
bootstrapDns: '', bootstrapDns: '',
allServers: false, allServers: false,
@ -181,16 +209,15 @@ const dashboard = handleActions({
dnsVersion: '', dnsVersion: '',
clients: [], clients: [],
autoClients: [], autoClients: [],
}); },
);
const dhcp = handleActions({ const dhcp = handleActions(
{
[actions.getDhcpStatusRequest]: state => ({ ...state, processing: true }), [actions.getDhcpStatusRequest]: state => ({ ...state, processing: true }),
[actions.getDhcpStatusFailure]: state => ({ ...state, processing: false }), [actions.getDhcpStatusFailure]: state => ({ ...state, processing: false }),
[actions.getDhcpStatusSuccess]: (state, { payload }) => { [actions.getDhcpStatusSuccess]: (state, { payload }) => {
const { const { static_leases: staticLeases, ...values } = payload;
static_leases: staticLeases,
...values
} = payload;
const newState = { const newState = {
...state, ...state,
@ -216,10 +243,7 @@ const dhcp = handleActions({
[actions.findActiveDhcpRequest]: state => ({ ...state, processingStatus: true }), [actions.findActiveDhcpRequest]: state => ({ ...state, processingStatus: true }),
[actions.findActiveDhcpFailure]: state => ({ ...state, processingStatus: false }), [actions.findActiveDhcpFailure]: state => ({ ...state, processingStatus: false }),
[actions.findActiveDhcpSuccess]: (state, { payload }) => { [actions.findActiveDhcpSuccess]: (state, { payload }) => {
const { const { other_server: otherServer, static_ip: staticIP } = payload;
other_server: otherServer,
static_ip: staticIP,
} = payload;
const newState = { const newState = {
...state, ...state,
@ -238,7 +262,10 @@ const dhcp = handleActions({
const { config } = state; const { config } = state;
const newConfig = { ...config, enabled: !config.enabled }; const newConfig = { ...config, enabled: !config.enabled };
const newState = { const newState = {
...state, config: newConfig, check: null, processingDhcp: false, ...state,
config: newConfig,
check: null,
processingDhcp: false,
}; };
return newState; return newState;
}, },
@ -263,9 +290,7 @@ const dhcp = handleActions({
[actions.addStaticLeaseRequest]: state => ({ ...state, processingAdding: true }), [actions.addStaticLeaseRequest]: state => ({ ...state, processingAdding: true }),
[actions.addStaticLeaseFailure]: state => ({ ...state, processingAdding: false }), [actions.addStaticLeaseFailure]: state => ({ ...state, processingAdding: false }),
[actions.addStaticLeaseSuccess]: (state, { payload }) => { [actions.addStaticLeaseSuccess]: (state, { payload }) => {
const { const { ip, mac, hostname } = payload;
ip, mac, hostname,
} = payload;
const newLease = { const newLease = {
ip, ip,
mac, mac,
@ -292,7 +317,8 @@ const dhcp = handleActions({
}; };
return newState; return newState;
}, },
}, { },
{
processing: true, processing: true,
processingStatus: false, processingStatus: false,
processingInterfaces: false, processingInterfaces: false,
@ -307,7 +333,8 @@ const dhcp = handleActions({
leases: [], leases: [],
staticLeases: [], staticLeases: [],
isModalOpen: false, isModalOpen: false,
}); },
);
export default combineReducers({ export default combineReducers({
settings, settings,