From 756c5ac0d3c9b685f95cc755ad098cef74e0c517 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov <i.kamalov@adguard.com> Date: Tue, 19 Mar 2019 16:19:53 +0300 Subject: [PATCH] + client: added setup guide page and DNS addresses popover Closes #605 --- client/src/__locales/en.json | 4 +- client/src/components/App/index.js | 4 +- client/src/components/Header/Header.css | 7 ++ client/src/components/Header/Menu.js | 7 +- client/src/components/Header/Version.js | 23 ++++-- client/src/components/Header/index.js | 12 ++-- client/src/components/SetupGuide/Guide.css | 15 ++++ client/src/components/SetupGuide/index.js | 46 ++++++++++++ client/src/components/ui/Guide.js | 83 ++++++++++++++++++++++ client/src/components/ui/Popover.css | 46 ++++++++++++ client/src/containers/SetupGuide.js | 14 ++++ client/src/install/Setup/Devices.js | 75 +------------------ client/src/reducers/index.js | 7 +- 13 files changed, 251 insertions(+), 92 deletions(-) create mode 100644 client/src/components/SetupGuide/Guide.css create mode 100644 client/src/components/SetupGuide/index.js create mode 100644 client/src/components/ui/Guide.js create mode 100644 client/src/containers/SetupGuide.js diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 92540ea6..36b78e79 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -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" } diff --git a/client/src/components/App/index.js b/client/src/components/App/index.js index 91c5e512..a2676dd0 100644 --- a/client/src/components/App/index.js +++ b/client/src/components/App/index.js @@ -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> diff --git a/client/src/components/Header/Header.css b/client/src/components/Header/Header.css index dbbcf08d..a8273e78 100644 --- a/client/src/components/Header/Header.css +++ b/client/src/components/Header/Header.css @@ -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; } diff --git a/client/src/components/Header/Menu.js b/client/src/components/Header/Menu.js index ef465378..2800d768 100644 --- a/client/src/components/Header/Menu.js +++ b/client/src/components/Header/Menu.js @@ -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> diff --git a/client/src/components/Header/Version.js b/client/src/components/Header/Version.js index 0faedbcc..be2158e9 100644 --- a/client/src/components/Header/Version.js +++ b/client/src/components/Header/Version.js @@ -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); diff --git a/client/src/components/Header/index.js b/client/src/components/Header/index.js index ecc1a2af..e2d47fe6 100644 --- a/client/src/components/Header/index.js +++ b/client/src/components/Header/index.js @@ -56,11 +56,13 @@ class Header extends Component { toggleMenuOpen={this.toggleMenuOpen} closeMenu={this.closeMenu} /> - <div className="col col-sm-6 col-lg-3"> - <Version - { ...this.props.dashboard } - /> - </div> + {!dashboard.processing && + <div className="col col-sm-6 col-lg-3"> + <Version + { ...this.props.dashboard } + /> + </div> + } </div> </div> </div> diff --git a/client/src/components/SetupGuide/Guide.css b/client/src/components/SetupGuide/Guide.css new file mode 100644 index 00000000..821f1798 --- /dev/null +++ b/client/src/components/SetupGuide/Guide.css @@ -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; +} diff --git a/client/src/components/SetupGuide/index.js b/client/src/components/SetupGuide/index.js new file mode 100644 index 00000000..bea2bbb1 --- /dev/null +++ b/client/src/components/SetupGuide/index.js @@ -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); diff --git a/client/src/components/ui/Guide.js b/client/src/components/ui/Guide.js new file mode 100644 index 00000000..9e89f7ec --- /dev/null +++ b/client/src/components/ui/Guide.js @@ -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); diff --git a/client/src/components/ui/Popover.css b/client/src/components/ui/Popover.css index dc83e4cb..f7e23836 100644 --- a/client/src/components/ui/Popover.css +++ b/client/src/components/ui/Popover.css @@ -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; } diff --git a/client/src/containers/SetupGuide.js b/client/src/containers/SetupGuide.js new file mode 100644 index 00000000..1e7ecd12 --- /dev/null +++ b/client/src/containers/SetupGuide.js @@ -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); diff --git a/client/src/install/Setup/Devices.js b/client/src/install/Setup/Devices.js index 4a5f7c13..f3755b3d 100644 --- a/client/src/install/Setup/Devices.js +++ b/client/src/install/Setup/Devices.js @@ -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> diff --git a/client/src/reducers/index.js b/client/src/reducers/index.js index 90ace4d6..a6daef82 100644 --- a/client/src/reducers/index.js +++ b/client/src/reducers/index.js @@ -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({