Show list of addresses

This commit is contained in:
Ildar Kamalov 2019-02-04 17:13:59 +03:00 committed by Eugene Bujak
parent f379d34813
commit 31b855f9ab
9 changed files with 166 additions and 72 deletions

View File

@ -164,10 +164,10 @@
"install_settings_title": "Admin Web Interface", "install_settings_title": "Admin Web Interface",
"install_settings_listen": "Listen interface", "install_settings_listen": "Listen interface",
"install_settings_port": "Port", "install_settings_port": "Port",
"install_settings_interface_link": "Your AdGuard Home admin web interface will be available on the following addresses: <0>{{link}}</0>", "install_settings_interface_link": "Your AdGuard Home admin web interface will be available on the following addresses:",
"form_error_port": "Enter valid port value", "form_error_port": "Enter valid port value",
"install_settings_dns": "DNS server", "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}}</0>", "install_settings_dns_desc": "You will need to configure your devices or router to use the DNS server on the following addresses:",
"install_settings_all_interfaces": "All interfaces", "install_settings_all_interfaces": "All interfaces",
"install_auth_title": "Authentication", "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_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.",

View File

@ -70,3 +70,5 @@ export const SETTINGS_NAMES = {
parental: 'parental', parental: 'parental',
safesearch: 'safesearch', safesearch: 'safesearch',
}; };
export const STANDARD_DNS_PORT = 53;

View File

@ -4,7 +4,7 @@ import subHours from 'date-fns/sub_hours';
import addHours from 'date-fns/add_hours'; import addHours from 'date-fns/add_hours';
import round from 'lodash/round'; import round from 'lodash/round';
import { STATS_NAMES } from './constants'; import { STATS_NAMES, STANDARD_DNS_PORT } from './constants';
export const formatTime = (time) => { export const formatTime = (time) => {
const parsedTime = dateParse(time); const parsedTime = dateParse(time);
@ -85,3 +85,46 @@ export const getPercent = (amount, number) => {
}; };
export const captitalizeWords = text => text.split(/[ -_]/g).map(str => str.charAt(0).toUpperCase() + str.substr(1)).join(' '); export const captitalizeWords = text => text.split(/[ -_]/g).map(str => str.charAt(0).toUpperCase() + str.substr(1)).join(' ');
export const getInterfaceIp = (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 interfaceIP;
};
export const getIpList = (interfaces) => {
let list = [];
Object.keys(interfaces).forEach((item) => {
list = [...list, ...interfaces[item].ip_addresses];
});
return list.sort();
};
export const getAddress = (ip, port = '', isDns = false) => {
if (!port) {
return isDns ? ip : `http://${ip}`;
}
if (isDns) {
if (ip.includes(':') && port !== STANDARD_DNS_PORT) {
return `[${ip}]:${port}`;
} else if (port !== STANDARD_DNS_PORT) {
return `${ip}:${port}`;
}
return ip;
}
return ip.includes(':') ? `http://[${ip}]:${port}` : `http://${ip}:${port}`;
};

View File

@ -0,0 +1,60 @@
import React from 'react';
import PropTypes from 'prop-types';
import { getIpList, getAddress } from '../../helpers/helpers';
const AddressList = (props) => {
let webAddress = getAddress(props.address, props.port);
let dnsAddress = getAddress(props.address, props.port, true);
if (props.address === '0.0.0.0') {
return getIpList(props.interfaces).map((ip) => {
webAddress = getAddress(ip, props.port);
dnsAddress = getAddress(ip, props.port, true);
if (props.isDns) {
return (
<li key={ip}>
<strong>
{dnsAddress}
</strong>
</li>
);
}
return (
<li key={ip}>
<a href={webAddress}>
{webAddress}
</a>
</li>
);
});
}
if (props.isDns) {
return (
<strong>
{dnsAddress}
</strong>
);
}
return (
<a href={webAddress}>
{webAddress}
</a>
);
};
AddressList.propTypes = {
interfaces: PropTypes.object.isRequired,
address: PropTypes.string.isRequired,
port: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
isDns: PropTypes.bool,
};
export default AddressList;

View File

@ -4,26 +4,12 @@ import PropTypes from 'prop-types';
import { Trans } from 'react-i18next'; import { Trans } from 'react-i18next';
import * as actionCreators from '../../actions/install'; import * as actionCreators from '../../actions/install';
import { INSTALL_FIRST_STEP, INSTALL_TOTAL_STEPS } from '../../helpers/constants';
class Controls extends Component { class Controls extends Component {
nextStep = () => {
if (this.props.step < INSTALL_TOTAL_STEPS) {
this.props.nextStep();
}
}
prevStep = () => {
if (this.props.step > INSTALL_FIRST_STEP) {
this.props.prevStep();
}
}
renderPrevButton(step) { renderPrevButton(step) {
switch (step) { switch (step) {
case 2: case 2:
case 3: case 3:
case 4:
return ( return (
<button <button
type="button" type="button"
@ -76,7 +62,7 @@ class Controls extends Component {
<button <button
type="button" type="button"
className="btn btn-success btn-standard btn-lg" className="btn btn-success btn-standard btn-lg"
onClick={this.props.openDashboard} onClick={() => this.props.openDashboard(this.props.address)}
> >
<Trans>open_dashboard</Trans> <Trans>open_dashboard</Trans>
</button> </button>
@ -106,6 +92,7 @@ Controls.propTypes = {
submitting: PropTypes.bool, submitting: PropTypes.bool,
invalid: PropTypes.bool, invalid: PropTypes.bool,
pristine: PropTypes.bool, pristine: PropTypes.bool,
address: PropTypes.string,
}; };
const mapStateToProps = (state) => { const mapStateToProps = (state) => {

View File

@ -8,6 +8,7 @@ import flow from 'lodash/flow';
import Tabs from '../../components/ui/Tabs'; import Tabs from '../../components/ui/Tabs';
import Icons from '../../components/ui/Icons'; import Icons from '../../components/ui/Icons';
import Controls from './Controls'; import Controls from './Controls';
import AddressList from './AddressList';
let Devices = props => ( let Devices = props => (
<div className="setup__step"> <div className="setup__step">
@ -20,8 +21,13 @@ let Devices = props => (
<div className="mt-1"> <div className="mt-1">
<Trans>install_devices_address</Trans>: <Trans>install_devices_address</Trans>:
</div> </div>
<div> <div className="mt-1">
<strong>{`${props.dnsIp}:${props.dnsPort}`}</strong> <AddressList
interfaces={props.interfaces}
address={props.dnsIp}
port={props.dnsPort}
isDns={true}
/>
</div> </div>
</div> </div>
<Icons /> <Icons />
@ -101,6 +107,7 @@ let Devices = props => (
); );
Devices.propTypes = { Devices.propTypes = {
interfaces: PropTypes.object.isRequired,
dnsIp: PropTypes.string.isRequired, dnsIp: PropTypes.string.isRequired,
dnsPort: PropTypes.number.isRequired, dnsPort: PropTypes.number.isRequired,
}; };

View File

@ -6,7 +6,9 @@ import { Trans, withNamespaces } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import Controls from './Controls'; import Controls from './Controls';
import AddressList from './AddressList';
import renderField from './renderField'; import renderField from './renderField';
import { getInterfaceIp } from '../../helpers/helpers';
const required = (value) => { const required = (value) => {
if (value || value === 0) { if (value || value === 0) {
@ -28,20 +30,11 @@ const renderInterfaces = (interfaces => (
Object.keys(interfaces).map((item) => { Object.keys(interfaces).map((item) => {
const option = interfaces[item]; const option = interfaces[item];
const { name } = option; const { name } = option;
const onlyIPv6 = option.ip_addresses.every(ip => ip.includes(':')); const ip = getInterfaceIp(option);
let interfaceIP = option.ip_addresses[0];
if (!onlyIPv6) {
option.ip_addresses.forEach((ip) => {
if (!ip.includes(':')) {
interfaceIP = ip;
}
});
}
return ( return (
<option value={interfaceIP} key={name}> <option value={ip} key={name}>
{name} - {interfaceIP} {name} - {ip}
</option> </option>
); );
}) })
@ -50,8 +43,8 @@ const renderInterfaces = (interfaces => (
let Settings = (props) => { let Settings = (props) => {
const { const {
handleSubmit, handleSubmit,
interfaceIp, webIp,
interfacePort, webPort,
dnsIp, dnsIp,
dnsPort, dnsPort,
interfaces, interfaces,
@ -59,8 +52,6 @@ let Settings = (props) => {
webWarning, webWarning,
dnsWarning, dnsWarning,
} = props; } = props;
const dnsAddress = dnsPort && dnsPort !== 53 ? `${dnsIp}:${dnsPort}` : dnsIp;
const interfaceAddress = interfacePort ? `http://${interfaceIp}:${interfacePort}` : `http://${interfaceIp}`;
return ( return (
<form className="setup__step" onSubmit={handleSubmit}> <form className="setup__step" onSubmit={handleSubmit}>
@ -104,12 +95,14 @@ let Settings = (props) => {
</div> </div>
</div> </div>
<div className="setup__desc"> <div className="setup__desc">
<Trans <Trans>install_settings_interface_link</Trans>
components={[<a href={`http://${interfaceIp}`} key="0">link</a>]} <div className="mt-1">
values={{ link: interfaceAddress }} <AddressList
> interfaces={interfaces}
install_settings_interface_link address={webIp}
</Trans> port={webPort}
/>
</div>
{webWarning && {webWarning &&
<div className="text-danger mt-2"> <div className="text-danger mt-2">
{webWarning} {webWarning}
@ -132,7 +125,7 @@ let Settings = (props) => {
component="select" component="select"
className="form-control custom-select" className="form-control custom-select"
> >
<option value="0.0.0.0" defaultValue> <option value="0.0.0.0">
<Trans>install_settings_all_interfaces</Trans> <Trans>install_settings_all_interfaces</Trans>
</option> </option>
{renderInterfaces(interfaces)} {renderInterfaces(interfaces)}
@ -157,12 +150,15 @@ let Settings = (props) => {
</div> </div>
</div> </div>
<div className="setup__desc"> <div className="setup__desc">
<Trans <Trans>install_settings_dns_desc</Trans>
components={[<strong key="0">ip</strong>]} <div className="mt-1">
values={{ ip: dnsAddress }} <AddressList
> interfaces={interfaces}
install_settings_dns_desc address={dnsIp}
</Trans> port={dnsPort}
isDns={true}
/>
</div>
{dnsWarning && {dnsWarning &&
<div className="text-danger mt-2"> <div className="text-danger mt-2">
{dnsWarning} {dnsWarning}
@ -177,9 +173,9 @@ let Settings = (props) => {
Settings.propTypes = { Settings.propTypes = {
handleSubmit: PropTypes.func.isRequired, handleSubmit: PropTypes.func.isRequired,
interfaceIp: PropTypes.string.isRequired, webIp: PropTypes.string.isRequired,
dnsIp: PropTypes.string.isRequired, dnsIp: PropTypes.string.isRequired,
interfacePort: PropTypes.oneOfType([ webPort: PropTypes.oneOfType([
PropTypes.string, PropTypes.string,
PropTypes.number, PropTypes.number,
]), ]),
@ -197,14 +193,14 @@ Settings.propTypes = {
const selector = formValueSelector('install'); const selector = formValueSelector('install');
Settings = connect((state) => { Settings = connect((state) => {
const interfaceIp = selector(state, 'web.ip'); const webIp = selector(state, 'web.ip');
const interfacePort = selector(state, 'web.port'); const webPort = selector(state, 'web.port');
const dnsIp = selector(state, 'dns.ip'); const dnsIp = selector(state, 'dns.ip');
const dnsPort = selector(state, 'dns.port'); const dnsPort = selector(state, 'dns.port');
return { return {
interfaceIp, webIp,
interfacePort, webPort,
dnsIp, dnsIp,
dnsPort, dnsPort,
}; };

View File

@ -6,6 +6,7 @@ import { Trans, withNamespaces } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import Controls from './Controls'; import Controls from './Controls';
import { getAddress } from '../../helpers/helpers';
let Submit = props => ( let Submit = props => (
<div className="setup__step"> <div className="setup__step">
@ -17,33 +18,31 @@ let Submit = props => (
<Trans>install_submit_desc</Trans> <Trans>install_submit_desc</Trans>
</p> </p>
</div> </div>
<form onSubmit={props.handleSubmit}> <Controls
<Controls openDashboard={props.openDashboard}
submitting={props.submitting} address={getAddress(props.webIp, props.webPort)}
pristine={props.pristine} />
address={`http://${props.interfaceIp}`}
/>
</form>
</div> </div>
); );
Submit.propTypes = { Submit.propTypes = {
interfaceIp: PropTypes.string.isRequired, webIp: PropTypes.string.isRequired,
interfacePort: PropTypes.number.isRequired, webPort: PropTypes.number.isRequired,
handleSubmit: PropTypes.func.isRequired, handleSubmit: PropTypes.func.isRequired,
pristine: PropTypes.bool.isRequired, pristine: PropTypes.bool.isRequired,
submitting: PropTypes.bool.isRequired, submitting: PropTypes.bool.isRequired,
openDashboard: PropTypes.func.isRequired,
}; };
const selector = formValueSelector('install'); const selector = formValueSelector('install');
Submit = connect((state) => { Submit = connect((state) => {
const interfaceIp = selector(state, 'web.ip'); const webIp = selector(state, 'web.ip');
const interfacePort = selector(state, 'web.port'); const webPort = selector(state, 'web.port');
return { return {
interfaceIp, webIp,
interfacePort, webPort,
}; };
})(Submit); })(Submit);

View File

@ -29,8 +29,8 @@ class Setup extends Component {
this.props.setAllSettings(values); this.props.setAllSettings(values);
}; };
openDashboard = () => { openDashboard = (address) => {
console.log('Open dashboard'); window.location.replace(address);
} }
nextStep = () => { nextStep = () => {
@ -64,9 +64,9 @@ class Setup extends Component {
<Auth onSubmit={this.handleFormSubmit} /> <Auth onSubmit={this.handleFormSubmit} />
); );
case 4: case 4:
return <Devices />; return <Devices interfaces={interfaces} />;
case 5: case 5:
return <Submit onSubmit={this.openDashboard} />; return <Submit openDashboard={this.openDashboard} />;
default: default:
return false; return false;
} }