From f379d34813753e904ff82ffe779819f692db4d67 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Fri, 1 Feb 2019 19:52:42 +0300 Subject: [PATCH] Added select for listen interfaces --- client/src/__locales/en.json | 4 +- client/src/actions/install.js | 2 + client/src/api/Api.js | 8 +-- client/src/install/Setup/Controls.js | 79 +++++++++++++------------ client/src/install/Setup/Devices.js | 42 ++++++++++++-- client/src/install/Setup/Settings.js | 86 ++++++++++++++++++---------- client/src/install/Setup/Setup.css | 1 + client/src/install/Setup/Submit.js | 64 ++++++++++++--------- client/src/install/Setup/index.js | 16 ++++-- client/src/reducers/install.js | 16 +++++- 10 files changed, 211 insertions(+), 107 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index aa4e7072..fc41fd85 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -164,10 +164,11 @@ "install_settings_title": "Admin Web Interface", "install_settings_listen": "Listen interface", "install_settings_port": "Port", - "install_settings_interface_link": "Your AdGuard Home admin web interface is available on <0>{{link}}", + "install_settings_interface_link": "Your AdGuard Home admin web interface will be available on the following addresses: <0>{{link}}", "form_error_port": "Enter valid port value", "install_settings_dns": "DNS server", "install_settings_dns_desc": "You will need to configure your devices or router to use the DNS server at <0>{{ip}}", + "install_settings_all_interfaces": "All interfaces", "install_auth_title": "Authentication", "install_auth_desc": "It is highly recommended to configure password authentication to your AdGuard Home admin web interface. Even if it is accessible only in your local network, it is still important to have it protected from unrestricted access.", "install_auth_username": "Username", @@ -182,6 +183,7 @@ "install_submit_desc": "The setup procedure is finished and you are ready to start using AdGuard Home.", "install_devices_router": "Router", "install_devices_router_desc": "This setup will automatically cover all the devices connected to your home router and you will not need to configure each of them manually.", + "install_devices_address": "AdGuard Home DNS server is listening to the following addresses", "install_devices_router_list_1": "Open the preferences for your router. Usually, you can access it from your browser via a URL (like http://192.168.0.1/ or http://192.168.1.1/). You may be asked to enter the password. If you don't remember it, you can often reset the password by pressing a button on the router itself. Some routers require a specific application, which in that case should be already installed on your computer/phone.", "install_devices_router_list_2": "Find the DHCP/DNS settings. Look for the DNS letters next to a field which allows two or three sets of numbers, each broken into four groups of one to three digits.", "install_devices_router_list_3": "Enter your AdGuard Home server addresses there.", diff --git a/client/src/actions/install.js b/client/src/actions/install.js index 144c89fc..3b612927 100644 --- a/client/src/actions/install.js +++ b/client/src/actions/install.js @@ -48,8 +48,10 @@ export const setAllSettings = values => async (dispatch) => { await apiClient.setAllSettings(config); dispatch(setAllSettingsSuccess()); dispatch(addSuccessToast('install_saved')); + dispatch(nextStep()); } catch (error) { dispatch(addErrorToast({ error })); dispatch(setAllSettingsFailure()); + dispatch(prevStep()); } }; diff --git a/client/src/api/Api.js b/client/src/api/Api.js index 7f1da9c5..0dac781a 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -338,16 +338,16 @@ export default class Api { } // Installation - GET_DEFAULT_ADDRESSES = { path: 'install/get_default_addresses', method: 'GET' }; - SET_ALL_SETTINGS = { path: 'install/set_all_settings', method: 'POST' }; + INSTALL_GET_ADDRESSES = { path: 'install/get_addresses', method: 'GET' }; + INSTALL_CONFIGURE = { path: 'install/configure', method: 'POST' }; getDefaultAddresses() { - const { path, method } = this.GET_DEFAULT_ADDRESSES; + const { path, method } = this.INSTALL_GET_ADDRESSES; return this.makeRequest(path, method); } setAllSettings(config) { - const { path, method } = this.SET_ALL_SETTINGS; + const { path, method } = this.INSTALL_CONFIGURE; const parameters = { data: config, headers: { 'Content-Type': 'application/json' }, diff --git a/client/src/install/Setup/Controls.js b/client/src/install/Setup/Controls.js index e74931fa..7c6a7e30 100644 --- a/client/src/install/Setup/Controls.js +++ b/client/src/install/Setup/Controls.js @@ -19,7 +19,26 @@ class Controls extends Component { } } - renderButtons(step) { + renderPrevButton(step) { + switch (step) { + case 2: + case 3: + case 4: + return ( + + ); + default: + return false; + } + } + + renderNextButton(step) { switch (step) { case 1: return ( @@ -34,48 +53,30 @@ class Controls extends Component { case 2: case 3: return ( -
- - -
+ ); case 4: return ( -
- - -
+ ); case 5: return ( @@ -88,7 +89,10 @@ class Controls extends Component { render() { return (
- {this.renderButtons(this.props.step)} +
+ {this.renderPrevButton(this.props.step)} + {this.renderNextButton(this.props.step)} +
); } @@ -98,9 +102,10 @@ Controls.propTypes = { step: PropTypes.number.isRequired, nextStep: PropTypes.func, prevStep: PropTypes.func, - pristine: PropTypes.bool, + openDashboard: PropTypes.func, submitting: PropTypes.bool, invalid: PropTypes.bool, + pristine: PropTypes.bool, }; const mapStateToProps = (state) => { diff --git a/client/src/install/Setup/Devices.js b/client/src/install/Setup/Devices.js index 54788ce8..1ce76bcc 100644 --- a/client/src/install/Setup/Devices.js +++ b/client/src/install/Setup/Devices.js @@ -1,19 +1,29 @@ import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { reduxForm, formValueSelector } from 'redux-form'; import { Trans, withNamespaces } from 'react-i18next'; +import flow from 'lodash/flow'; import Tabs from '../../components/ui/Tabs'; import Icons from '../../components/ui/Icons'; import Controls from './Controls'; -const Devices = () => ( +let Devices = props => (
install_devices_title
-

+

install_devices_desc -

+
+ install_devices_address: +
+
+ {`${props.dnsIp}:${props.dnsPort}`} +
+
@@ -90,4 +100,28 @@ const Devices = () => (
); -export default withNamespaces()(Devices); +Devices.propTypes = { + dnsIp: PropTypes.string.isRequired, + dnsPort: PropTypes.number.isRequired, +}; + +const selector = formValueSelector('install'); + +Devices = connect((state) => { + const dnsIp = selector(state, 'dns.ip'); + const dnsPort = selector(state, 'dns.port'); + + return { + dnsIp, + dnsPort, + }; +})(Devices); + +export default flow([ + withNamespaces(), + reduxForm({ + form: 'install', + destroyOnUnmount: false, + forceUnregisterOnUnmount: true, + }), +])(Devices); diff --git a/client/src/install/Setup/Settings.js b/client/src/install/Setup/Settings.js index 0d2804b0..122465e1 100644 --- a/client/src/install/Setup/Settings.js +++ b/client/src/install/Setup/Settings.js @@ -7,7 +7,6 @@ import flow from 'lodash/flow'; import Controls from './Controls'; import renderField from './renderField'; -import { R_IPV4 } from '../../helpers/constants'; const required = (value) => { if (value || value === 0) { @@ -16,13 +15,6 @@ const required = (value) => { return form_error_required; }; -const ipv4 = (value) => { - if (value && !new RegExp(R_IPV4).test(value)) { - return form_error_ip_format; - } - return false; -}; - const port = (value) => { if (value < 1 || value > 65535) { return form_error_port; @@ -32,6 +24,29 @@ const port = (value) => { const toNumber = value => value && parseInt(value, 10); +const renderInterfaces = (interfaces => ( + Object.keys(interfaces).map((item) => { + const option = interfaces[item]; + const { name } = option; + const onlyIPv6 = option.ip_addresses.every(ip => ip.includes(':')); + let interfaceIP = option.ip_addresses[0]; + + if (!onlyIPv6) { + option.ip_addresses.forEach((ip) => { + if (!ip.includes(':')) { + interfaceIP = ip; + } + }); + } + + return ( + + ); + }) +)); + let Settings = (props) => { const { handleSubmit, @@ -39,7 +54,10 @@ let Settings = (props) => { interfacePort, dnsIp, dnsPort, + interfaces, invalid, + webWarning, + dnsWarning, } = props; const dnsAddress = dnsPort && dnsPort !== 53 ? `${dnsIp}:${dnsPort}` : dnsIp; const interfaceAddress = interfacePort ? `http://${interfaceIp}:${interfacePort}` : `http://${interfaceIp}`; @@ -58,12 +76,14 @@ let Settings = (props) => { + component="select" + className="form-control custom-select" + > + + {renderInterfaces(interfaces)} +
@@ -90,6 +110,11 @@ let Settings = (props) => { > install_settings_interface_link + {webWarning && +
+ {webWarning} +
+ }
@@ -104,12 +129,14 @@ let Settings = (props) => { + component="select" + className="form-control custom-select" + > + + {renderInterfaces(interfaces)} +
@@ -129,14 +156,19 @@ let Settings = (props) => {
-

+

ip]} values={{ ip: dnsAddress }} > install_settings_dns_desc -

+ {dnsWarning && +
+ {dnsWarning} +
+ } +
@@ -155,17 +187,13 @@ Settings.propTypes = { PropTypes.string, PropTypes.number, ]), + webWarning: PropTypes.string.isRequired, + dnsWarning: PropTypes.string.isRequired, + interfaces: PropTypes.object.isRequired, invalid: PropTypes.bool.isRequired, initialValues: PropTypes.object, }; -Settings.defaultProps = { - interfaceIp: '192.168.0.1', - interfacePort: 3000, - dnsIp: '192.168.0.1', - dnsPort: 53, -}; - const selector = formValueSelector('install'); Settings = connect((state) => { diff --git a/client/src/install/Setup/Setup.css b/client/src/install/Setup/Setup.css index b0926986..065ec6f6 100644 --- a/client/src/install/Setup/Setup.css +++ b/client/src/install/Setup/Setup.css @@ -54,6 +54,7 @@ } .setup__desc { + margin-bottom: 20px; font-size: 15px; } diff --git a/client/src/install/Setup/Submit.js b/client/src/install/Setup/Submit.js index a497dc69..66d89331 100644 --- a/client/src/install/Setup/Submit.js +++ b/client/src/install/Setup/Submit.js @@ -1,43 +1,53 @@ -import React, { Component } from 'react'; +import React from 'react'; +import { connect } from 'react-redux'; import PropTypes from 'prop-types'; -import { reduxForm } from 'redux-form'; +import { reduxForm, formValueSelector } from 'redux-form'; import { Trans, withNamespaces } from 'react-i18next'; import flow from 'lodash/flow'; import Controls from './Controls'; -class Submit extends Component { - render() { - const { - handleSubmit, - pristine, - submitting, - } = this.props; - - return ( -
-
-

- install_submit_title -

-

- install_submit_desc -

-
-
- - -
- ); - } -} +let Submit = props => ( +
+
+

+ install_submit_title +

+

+ install_submit_desc +

+
+
+ + +
+); Submit.propTypes = { + interfaceIp: PropTypes.string.isRequired, + interfacePort: PropTypes.number.isRequired, handleSubmit: PropTypes.func.isRequired, pristine: PropTypes.bool.isRequired, submitting: PropTypes.bool.isRequired, }; +const selector = formValueSelector('install'); + +Submit = connect((state) => { + const interfaceIp = selector(state, 'web.ip'); + const interfacePort = selector(state, 'web.port'); + + return { + interfaceIp, + interfacePort, + }; +})(Submit); + + export default flow([ withNamespaces(), reduxForm({ diff --git a/client/src/install/Setup/index.js b/client/src/install/Setup/index.js index a5a5046c..0d5e4c80 100644 --- a/client/src/install/Setup/index.js +++ b/client/src/install/Setup/index.js @@ -29,6 +29,10 @@ class Setup extends Component { this.props.setAllSettings(values); }; + openDashboard = () => { + console.log('Open dashboard'); + } + nextStep = () => { if (this.props.install.step < INSTALL_TOTAL_STEPS) { this.props.nextStep(); @@ -41,7 +45,7 @@ class Setup extends Component { } } - renderPage(step, config) { + renderPage(step, config, interfaces) { switch (step) { case 1: return ; @@ -49,17 +53,20 @@ class Setup extends Component { return ( ); case 3: return ( - + ); case 4: return ; case 5: - return ; + return ; default: return false; } @@ -71,6 +78,7 @@ class Setup extends Component { step, web, dns, + interfaces, } = this.props.install; return ( @@ -81,7 +89,7 @@ class Setup extends Component {
logo - {this.renderPage(step, { web, dns })} + {this.renderPage(step, { web, dns }, interfaces)}
diff --git a/client/src/reducers/install.js b/client/src/reducers/install.js index dbfa52da..0df3c79e 100644 --- a/client/src/reducers/install.js +++ b/client/src/reducers/install.js @@ -10,7 +10,10 @@ const install = handleActions({ [actions.getDefaultAddressesRequest]: state => ({ ...state, processingDefault: true }), [actions.getDefaultAddressesFailure]: state => ({ ...state, processingDefault: false }), [actions.getDefaultAddressesSuccess]: (state, { payload }) => { - const newState = { ...state, ...payload, processingDefault: false }; + const values = payload; + values.web.ip = state.web.ip; + values.dns.ip = state.dns.ip; + const newState = { ...state, ...values, processingDefault: false }; return newState; }, @@ -23,6 +26,17 @@ const install = handleActions({ }, { step: INSTALL_FIRST_STEP, processingDefault: true, + web: { + ip: '0.0.0.0', + port: 80, + warning: '', + }, + dns: { + ip: '0.0.0.0', + port: 53, + warning: '', + }, + interfaces: {}, }); const toasts = handleActions({