From ab11c912db1af9a5b714d012851391630701943c Mon Sep 17 00:00:00 2001 From: Ildar Kamalov <i.kamalov@adguard.com> Date: Fri, 25 Jan 2019 15:18:05 +0300 Subject: [PATCH] Added topline component and fixed string interpolation --- client/src/__locales/en.json | 3 ++- client/src/actions/index.js | 9 +++++++- client/src/components/App/index.js | 21 +++++++++++++------ .../components/Settings/Encryption/Form.js | 17 ++++++++++----- .../components/ui/{Update.css => Topline.css} | 2 +- client/src/components/ui/Topline.js | 19 +++++++++++++++++ client/src/components/ui/Update.js | 19 ----------------- client/src/containers/App.js | 4 ++-- 8 files changed, 59 insertions(+), 35 deletions(-) rename client/src/components/ui/{Update.css => Topline.css} (89%) create mode 100644 client/src/components/ui/Topline.js delete mode 100644 client/src/components/ui/Update.js diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 36bd3501..25053476 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -223,13 +223,14 @@ "encryption_dot": "DNS-over-TLS port", "encryption_dot_desc": "If this port is configured, AdGuard Home will run a DNS-over-TLS server on this port.", "encryption_certificates": "Certificates", - "encryption_certificates_desc": "In order to use encryption, you need to provide a valid SSL certificates chain for your domain. You can get a free certificate on letsencrypt.org or you can buy it from one of the trusted Certificate Authorities.", + "encryption_certificates_desc": "In order to use encryption, you need to provide a valid SSL certificates chain for your domain. You can get a free certificate on <0>{{link}}</0> or you can buy it from one of the trusted Certificate Authorities.", "encryption_certificates_input": "Copy/paste your PEM-encoded cerificates here.", "encryption_status": "Status", "encryption_certificates_for": "Certificates for {{domains}}", "encryption_expire": "Expire on {{date}}", "encryption_key": "Private key", "encryption_key_input": "Copy/paste your PEM-encoded private key for your cerficate here.", + "topline_expiring_certificate": "Your SSL certificate is about to expire. Update <0>Encryption settings</0>.", "form_error_port_range": "Enter port value in the range of 80-65535", "form_error_equal": "Shouldn't be equal", "form_error_password": "Password mismatched" diff --git a/client/src/actions/index.js b/client/src/actions/index.js index da33f0fe..30527245 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -659,6 +659,9 @@ export const getTlsStatus = () => async (dispatch) => { dispatch(getTlsStatusRequest()); try { const status = await apiClient.getTlsStatus(); + status.certificate_chain = decodeURIComponent(status.certificate_chain); + status.private_key = decodeURIComponent(status.private_key); + dispatch(getTlsStatusSuccess(status)); } catch (error) { dispatch(addErrorToast({ error })); @@ -673,7 +676,11 @@ export const setTlsConfigSuccess = createAction('SET_TLS_CONFIG_SUCCESS'); export const setTlsConfig = config => async (dispatch) => { dispatch(setTlsConfigRequest()); try { - await apiClient.setTlsConfig(config); + const values = { ...config }; + values.certificate_chain = encodeURIComponent(values.certificate_chain); + values.private_key = encodeURIComponent(values.private_key); + + await apiClient.setTlsConfig(values); dispatch(setTlsConfigSuccess(config)); dispatch(addSuccessToast('encryption_config_saved')); } catch (error) { diff --git a/client/src/components/App/index.js b/client/src/components/App/index.js index 74bc6960..5bf0f925 100644 --- a/client/src/components/App/index.js +++ b/client/src/components/App/index.js @@ -1,6 +1,7 @@ import React, { Component, Fragment } from 'react'; import { HashRouter, Route } from 'react-router-dom'; import PropTypes from 'prop-types'; +import { Trans, withNamespaces } from 'react-i18next'; import LoadingBar from 'react-redux-loading-bar'; import 'react-table/react-table.css'; @@ -16,7 +17,7 @@ import Logs from '../../containers/Logs'; import Footer from '../ui/Footer'; import Toasts from '../Toasts'; import Status from '../ui/Status'; -import Update from '../ui/Update'; +import Topline from '../ui/Topline'; import i18n from '../../i18n'; class App extends Component { @@ -55,15 +56,22 @@ class App extends Component { !dashboard.processingVersions && dashboard.isCoreRunning && dashboard.isUpdateAvailable; + const isExpiringCertificate = false; return ( <HashRouter hashType='noslash'> <Fragment> {updateAvailable && - <Update - announcement={dashboard.announcement} - announcementUrl={dashboard.announcementUrl} - /> + <Topline type="info"> + {dashboard.announcement} <a href={dashboard.announcementUrl} target="_blank" rel="noopener noreferrer">Click here</a> for more info. + </Topline> + } + {isExpiringCertificate && + <Topline type="warning"> + <Trans components={[<a href="#settings" key="0">link</a>]}> + topline_expiring_certificate + </Trans> + </Topline> } <LoadingBar className="loading-bar" updateTime={1000} /> <Route component={Header} /> @@ -100,6 +108,7 @@ App.propTypes = { error: PropTypes.string, getVersion: PropTypes.func, changeLanguage: PropTypes.func, + encryption: PropTypes.object, }; -export default App; +export default withNamespaces()(App); diff --git a/client/src/components/Settings/Encryption/Form.js b/client/src/components/Settings/Encryption/Form.js index 3c814fad..e58aa8f4 100644 --- a/client/src/components/Settings/Encryption/Form.js +++ b/client/src/components/Settings/Encryption/Form.js @@ -114,7 +114,12 @@ const Form = (props) => { <Trans>encryption_certificates</Trans> </label> <div className="form__desc form__desc--top"> - <Trans>encryption_certificates_desc</Trans> + <Trans + values={{ link: 'letsencrypt.org' }} + components={[<a href="https://letsencrypt.org/" key="0">link</a>]} + > + encryption_certificates_desc + </Trans> </div> <Field id="certificate_chain" @@ -130,12 +135,14 @@ const Form = (props) => { <Trans>encryption_status</Trans>: </div> <div> - <Trans>encryption_certificates_for</Trans> - *.example.org, example.org + <Trans values={{ domains: '*.example.org, example.org' }}> + encryption_certificates_for + </Trans> </div> <div> - <Trans>encryption_expire</Trans> - 2022-01-01 + <Trans values={{ date: '2022-01-01' }}> + encryption_expire + </Trans> </div> </div> </div> diff --git a/client/src/components/ui/Update.css b/client/src/components/ui/Topline.css similarity index 89% rename from client/src/components/ui/Update.css rename to client/src/components/ui/Topline.css index ec7ec532..33c4e8fd 100644 --- a/client/src/components/ui/Update.css +++ b/client/src/components/ui/Topline.css @@ -1,4 +1,4 @@ -.update { +.topline { position: relative; z-index: 102; margin-bottom: 0; diff --git a/client/src/components/ui/Topline.js b/client/src/components/ui/Topline.js new file mode 100644 index 00000000..13bfd827 --- /dev/null +++ b/client/src/components/ui/Topline.js @@ -0,0 +1,19 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import './Topline.css'; + +const Topline = props => ( + <div className={`alert alert-${props.type} topline`}> + <div className="container"> + {props.children} + </div> + </div> +); + +Topline.propTypes = { + children: PropTypes.node.isRequired, + type: PropTypes.string.isRequired, +}; + +export default Topline; diff --git a/client/src/components/ui/Update.js b/client/src/components/ui/Update.js deleted file mode 100644 index 5df9df65..00000000 --- a/client/src/components/ui/Update.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import './Update.css'; - -const Update = props => ( - <div className="alert alert-info update"> - <div className="container"> - {props.announcement} <a href={props.announcementUrl} target="_blank" rel="noopener noreferrer">Click here</a> for more info. - </div> - </div> -); - -Update.propTypes = { - announcement: PropTypes.string.isRequired, - announcementUrl: PropTypes.string.isRequired, -}; - -export default Update; diff --git a/client/src/containers/App.js b/client/src/containers/App.js index 905596c5..b6ce2cde 100644 --- a/client/src/containers/App.js +++ b/client/src/containers/App.js @@ -3,8 +3,8 @@ import * as actionCreators from '../actions'; import App from '../components/App'; const mapStateToProps = (state) => { - const { dashboard } = state; - const props = { dashboard }; + const { dashboard, encryption } = state; + const props = { dashboard, encryption }; return props; };