+ client: added setup guide page and DNS addresses popover

Closes #605
This commit is contained in:
Ildar Kamalov 2019-03-19 16:19:53 +03:00
parent b5eb840d22
commit 756c5ac0d3
13 changed files with 251 additions and 92 deletions

View File

@ -249,5 +249,7 @@
"update_announcement": "AdGuard Home {{version}} is now available! <0>Click here</0> for more info.",
"upstream_parallel": "Use parallel queries to speed up resolving by simultaneously querying all upstream servers",
"bootstrap_dns": "Bootstrap DNS servers",
"bootstrap_dns_desc": "Bootstrap DNS servers are used to resolve IP addresses of the DOH/DOT resolvers you specify as upstreams."
"bootstrap_dns_desc": "Bootstrap DNS servers are used to resolve IP addresses of the DOH/DOT resolvers you specify as upstreams.",
"setup_guide": "Setup guide",
"dns_addresses": "DNS addresses"
}

View File

@ -14,8 +14,9 @@ import Dashboard from '../../containers/Dashboard';
import Settings from '../../containers/Settings';
import Filters from '../../containers/Filters';
import Logs from '../../containers/Logs';
import Footer from '../ui/Footer';
import SetupGuide from '../../containers/SetupGuide';
import Toasts from '../Toasts';
import Footer from '../ui/Footer';
import Status from '../ui/Status';
import UpdateTopline from '../ui/UpdateTopline';
import EncryptionTopline from '../ui/EncryptionTopline';
@ -86,6 +87,7 @@ class App extends Component {
<Route path="/settings" component={Settings} />
<Route path="/filters" component={Filters} />
<Route path="/logs" component={Logs} />
<Route path="/guide" component={SetupGuide} />
</Fragment>
}
</div>

View File

@ -76,6 +76,13 @@
font-weight: 600;
}
.nav-version__link {
position: relative;
display: inline-block;
border-bottom: 1px dashed #495057;
cursor: pointer;
}
.header-brand-img {
height: 32px;
}

View File

@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import enhanceWithClickOutside from 'react-click-outside';
import classnames from 'classnames';
import { Trans, withNamespaces } from 'react-i18next';
import { REPOSITORY } from '../../helpers/constants';
class Menu extends Component {
handleClickOutside = () => {
@ -56,10 +55,10 @@ class Menu extends Component {
</NavLink>
</li>
<li className="nav-item">
<a href={`${REPOSITORY.URL}/wiki`} className="nav-link" target="_blank" rel="noopener noreferrer">
<NavLink to="/guide" href="/guide" className="nav-link">
<svg className="nav-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#66b574" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12" y2="17"></line></svg>
<Trans>faq</Trans>
</a>
<Trans>setup_guide</Trans>
</NavLink>
</li>
</ul>
</div>

View File

@ -2,24 +2,35 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next';
import { getDnsAddress } from '../../helpers/helpers';
function Version(props) {
const { dnsVersion, dnsAddress, dnsPort } = props;
const { dnsVersion, dnsAddresses, dnsPort } = props;
return (
<div className="nav-version">
<div className="nav-version__text">
<Trans>version</Trans>: <span className="nav-version__value">{dnsVersion}</span>
</div>
<div className="nav-version__text">
<Trans>address</Trans>: <span className="nav-version__value">{dnsAddress}:{dnsPort}</span>
<div className="nav-version__link">
<div className="popover__trigger popover__trigger--address">
<Trans>dns_addresses</Trans>
</div>
<div className="popover__body popover__body--address">
<div className="popover__list">
{dnsAddresses
.map(ip => <li key={ip}>{getDnsAddress(ip, dnsPort)}</li>)
}
</div>
</div>
</div>
</div>
);
}
Version.propTypes = {
dnsVersion: PropTypes.string,
dnsAddress: PropTypes.string,
dnsPort: PropTypes.number,
dnsVersion: PropTypes.string.isRequired,
dnsAddresses: PropTypes.array.isRequired,
dnsPort: PropTypes.number.isRequired,
};
export default withNamespaces()(Version);

View File

@ -56,11 +56,13 @@ class Header extends Component {
toggleMenuOpen={this.toggleMenuOpen}
closeMenu={this.closeMenu}
/>
{!dashboard.processing &&
<div className="col col-sm-6 col-lg-3">
<Version
{ ...this.props.dashboard }
/>
</div>
}
</div>
</div>
</div>

View File

@ -0,0 +1,15 @@
.guide {
max-width: 768px;
margin: 0 auto;
}
.guide__title {
margin-bottom: 10px;
font-size: 17px;
font-weight: 700;
}
.guide__desc {
margin-bottom: 20px;
font-size: 15px;
}

View File

@ -0,0 +1,46 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next';
import { getDnsAddress } from '../../helpers/helpers';
import Guide from '../ui/Guide';
import Card from '../ui/Card';
import PageTitle from '../ui/PageTitle';
import './Guide.css';
const SetupGuide = ({
t,
dashboard: {
dnsAddresses,
dnsPort,
},
}) => (
<div className="guide">
<PageTitle title={t('setup_guide')} />
<Card>
<div className="guide__title">
<Trans>install_devices_title</Trans>
</div>
<div className="guide__desc">
<Trans>install_devices_desc</Trans>
<div className="mt-1">
<Trans>install_devices_address</Trans>:
</div>
<div className="mt-2 font-weight-bold">
{dnsAddresses
.map(ip => <li key={ip}>{getDnsAddress(ip, dnsPort)}</li>)
}
</div>
</div>
<Guide />
</Card>
</div>
);
SetupGuide.propTypes = {
dashboard: PropTypes.object.isRequired,
t: PropTypes.func.isRequired,
};
export default withNamespaces()(SetupGuide);

View File

@ -0,0 +1,83 @@
import React from 'react';
import { Trans, withNamespaces } from 'react-i18next';
import Tabs from '../ui/Tabs';
import Icons from '../ui/Icons';
const Guide = () => (
<div>
<Icons />
<Tabs>
<div label="Router">
<div className="tab__title">
<Trans>install_devices_router</Trans>
</div>
<div className="tab__text">
<p><Trans>install_devices_router_desc</Trans></p>
<ol>
<li><Trans>install_devices_router_list_1</Trans></li>
<li><Trans>install_devices_router_list_2</Trans></li>
<li><Trans>install_devices_router_list_3</Trans></li>
</ol>
</div>
</div>
<div label="Windows">
<div className="tab__title">
Windows
</div>
<div className="tab__text">
<ol>
<li><Trans>install_devices_windows_list_1</Trans></li>
<li><Trans>install_devices_windows_list_2</Trans></li>
<li><Trans>install_devices_windows_list_3</Trans></li>
<li><Trans>install_devices_windows_list_4</Trans></li>
<li><Trans>install_devices_windows_list_5</Trans></li>
<li><Trans>install_devices_windows_list_6</Trans></li>
</ol>
</div>
</div>
<div label="macOS">
<div className="tab__title">
macOS
</div>
<div className="tab__text">
<ol>
<li><Trans>install_devices_macos_list_1</Trans></li>
<li><Trans>install_devices_macos_list_2</Trans></li>
<li><Trans>install_devices_macos_list_3</Trans></li>
<li><Trans>install_devices_macos_list_4</Trans></li>
</ol>
</div>
</div>
<div label="Android">
<div className="tab__title">
Android
</div>
<div className="tab__text">
<ol>
<li><Trans>install_devices_android_list_1</Trans></li>
<li><Trans>install_devices_android_list_2</Trans></li>
<li><Trans>install_devices_android_list_3</Trans></li>
<li><Trans>install_devices_android_list_4</Trans></li>
<li><Trans>install_devices_android_list_5</Trans></li>
</ol>
</div>
</div>
<div label="iOS">
<div className="tab__title">
iOS
</div>
<div className="tab__text">
<ol>
<li><Trans>install_devices_ios_list_1</Trans></li>
<li><Trans>install_devices_ios_list_2</Trans></li>
<li><Trans>install_devices_ios_list_3</Trans></li>
<li><Trans>install_devices_ios_list_4</Trans></li>
</ol>
</div>
</div>
</Tabs>
</div>
);
export default withNamespaces()(Guide);

View File

@ -22,6 +22,16 @@
height: 24px;
}
.popover__trigger--address {
top: 0;
margin: 0;
line-height: 1.2;
}
.popover__trigger--address:after {
display: none;
}
.popover__body {
content: "";
display: flex;
@ -57,6 +67,38 @@
border-top: 6px solid #585965;
}
.popover__body--address {
top: calc(100% + 10px);
right: 0;
left: initial;
bottom: initial;
z-index: 1;
min-width: 100px;
padding: 12px 18px;
font-weight: 700;
text-align: left;
white-space: nowrap;
transform: none;
cursor: default;
}
.popover__body--address:after {
top: -11px;
left: initial;
right: 40px;
border-top: 6px solid transparent;
border-bottom: 6px solid #585965;
}
.popover__body--address:before {
content: "";
position: absolute;
top: -7px;
left: 0;
width: 100%;
height: 10px;
}
.popover__trigger:hover + .popover__body,
.popover__body:hover {
visibility: visible;
@ -73,6 +115,10 @@
stroke: #66b574;
}
.popover__list--bold {
font-weight: 700;
}
.popover__list-title {
margin-bottom: 3px;
}

View File

@ -0,0 +1,14 @@
import { connect } from 'react-redux';
import * as actionCreators from '../actions';
import SetupGuide from '../components/SetupGuide';
const mapStateToProps = (state) => {
const { dashboard } = state;
const props = { dashboard };
return props;
};
export default connect(
mapStateToProps,
actionCreators,
)(SetupGuide);

View File

@ -5,8 +5,7 @@ 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 Guide from '../../components/ui/Guide';
import Controls from './Controls';
import AddressList from './AddressList';
@ -30,77 +29,7 @@ let Devices = props => (
/>
</div>
</div>
<Icons />
<Tabs>
<div label="Router">
<div className="tab__title">
<Trans>install_devices_router</Trans>
</div>
<div className="tab__text">
<p><Trans>install_devices_router_desc</Trans></p>
<ol>
<li><Trans>install_devices_router_list_1</Trans></li>
<li><Trans>install_devices_router_list_2</Trans></li>
<li><Trans>install_devices_router_list_3</Trans></li>
</ol>
</div>
</div>
<div label="Windows">
<div className="tab__title">
Windows
</div>
<div className="tab__text">
<ol>
<li><Trans>install_devices_windows_list_1</Trans></li>
<li><Trans>install_devices_windows_list_2</Trans></li>
<li><Trans>install_devices_windows_list_3</Trans></li>
<li><Trans>install_devices_windows_list_4</Trans></li>
<li><Trans>install_devices_windows_list_5</Trans></li>
<li><Trans>install_devices_windows_list_6</Trans></li>
</ol>
</div>
</div>
<div label="macOS">
<div className="tab__title">
macOS
</div>
<div className="tab__text">
<ol>
<li><Trans>install_devices_macos_list_1</Trans></li>
<li><Trans>install_devices_macos_list_2</Trans></li>
<li><Trans>install_devices_macos_list_3</Trans></li>
<li><Trans>install_devices_macos_list_4</Trans></li>
</ol>
</div>
</div>
<div label="Android">
<div className="tab__title">
Android
</div>
<div className="tab__text">
<ol>
<li><Trans>install_devices_android_list_1</Trans></li>
<li><Trans>install_devices_android_list_2</Trans></li>
<li><Trans>install_devices_android_list_3</Trans></li>
<li><Trans>install_devices_android_list_4</Trans></li>
<li><Trans>install_devices_android_list_5</Trans></li>
</ol>
</div>
</div>
<div label="iOS">
<div className="tab__title">
iOS
</div>
<div className="tab__text">
<ol>
<li><Trans>install_devices_ios_list_1</Trans></li>
<li><Trans>install_devices_ios_list_2</Trans></li>
<li><Trans>install_devices_ios_list_3</Trans></li>
<li><Trans>install_devices_ios_list_4</Trans></li>
</ol>
</div>
</div>
</Tabs>
<Guide />
</div>
<Controls />
</div>

View File

@ -48,7 +48,7 @@ const dashboard = handleActions({
version,
running,
dns_port: dnsPort,
dns_address: dnsAddress,
dns_addresses: dnsAddresses,
querylog_enabled: queryLogEnabled,
upstream_dns: upstreamDns,
bootstrap_dns: bootstrapDns,
@ -63,7 +63,7 @@ const dashboard = handleActions({
processing: false,
dnsVersion: version,
dnsPort,
dnsAddress,
dnsAddresses,
queryLogEnabled,
upstreamDns: upstreamDns.join('\n'),
bootstrapDns: bootstrapDns.join('\n'),
@ -181,6 +181,9 @@ const dashboard = handleActions({
protectionEnabled: false,
processingProtection: false,
httpPort: 80,
dnsPort: 53,
dnsAddresses: [],
dnsVersion: '',
});
const queryLogs = handleActions({