diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 63301db5..1e66a0e8 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -312,5 +312,7 @@ "access_disallowed_desc": "A list of CIDR or IP addresses. If configured, AdGuard Home will drop requests from these IP addresses.", "access_blocked_title": "Blocked domains", "access_blocked_desc": "Don't confuse this with filters. AdGuard Home will drop DNS queries with these domains in query's question.", - "access_settings_saved": "Access settings successfully saved" + "access_settings_saved": "Access settings successfully saved", + "updates_checked": "Updates successfully checked", + "check_updates_now": "Check updates now" } \ No newline at end of file diff --git a/client/src/actions/index.js b/client/src/actions/index.js index 3ceed2c4..aca824c6 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -145,11 +145,14 @@ export const getVersionRequest = createAction('GET_VERSION_REQUEST'); export const getVersionFailure = createAction('GET_VERSION_FAILURE'); export const getVersionSuccess = createAction('GET_VERSION_SUCCESS'); -export const getVersion = () => async (dispatch) => { +export const getVersion = (recheck = false) => async (dispatch) => { dispatch(getVersionRequest()); try { - const newVersion = await apiClient.getGlobalVersion(); + const newVersion = await apiClient.getGlobalVersion({ recheck_now: recheck }); dispatch(getVersionSuccess(newVersion)); + if (recheck) { + dispatch(addSuccessToast('updates_checked')); + } } catch (error) { dispatch(addErrorToast({ error })); dispatch(getVersionFailure()); diff --git a/client/src/api/Api.js b/client/src/api/Api.js index ad4e03fb..76b17888 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -36,7 +36,7 @@ export default class Api { GLOBAL_QUERY_LOG_DISABLE = { path: 'querylog_disable', method: 'POST' }; GLOBAL_SET_UPSTREAM_DNS = { path: 'set_upstreams_config', method: 'POST' }; GLOBAL_TEST_UPSTREAM_DNS = { path: 'test_upstream_dns', method: 'POST' }; - GLOBAL_VERSION = { path: 'version.json', method: 'GET' }; + GLOBAL_VERSION = { path: 'version.json', method: 'POST' }; GLOBAL_ENABLE_PROTECTION = { path: 'enable_protection', method: 'POST' }; GLOBAL_DISABLE_PROTECTION = { path: 'disable_protection', method: 'POST' }; GLOBAL_UPDATE = { path: 'update', method: 'POST' }; @@ -125,9 +125,13 @@ export default class Api { return this.makeRequest(path, method, config); } - getGlobalVersion() { + getGlobalVersion(data) { const { path, method } = this.GLOBAL_VERSION; - return this.makeRequest(path, method); + const config = { + data, + headers: { 'Content-Type': 'application/json' }, + }; + return this.makeRequest(path, method, config); } enableGlobalProtection() { diff --git a/client/src/components/App/index.js b/client/src/components/App/index.js index f77097a0..6489649c 100644 --- a/client/src/components/App/index.js +++ b/client/src/components/App/index.js @@ -65,8 +65,7 @@ class App extends Component { render() { const { dashboard, encryption } = this.props; - const updateAvailable = - !dashboard.processingVersions && dashboard.isCoreRunning && dashboard.isUpdateAvailable; + const updateAvailable = dashboard.isCoreRunning && dashboard.isUpdateAvailable; return ( <HashRouter hashType="noslash"> diff --git a/client/src/components/Dashboard/index.js b/client/src/components/Dashboard/index.js index 2509b7c7..ad207ba0 100644 --- a/client/src/components/Dashboard/index.js +++ b/client/src/components/Dashboard/index.js @@ -50,8 +50,26 @@ class Dashboard extends Component { dashboard.processingClients || dashboard.processingTopStats; - const refreshFullButton = <button type="button" className="btn btn-outline-primary btn-sm" onClick={() => this.getAllStats()}><Trans>refresh_statics</Trans></button>; - const refreshButton = <button type="button" className="btn btn-outline-primary btn-sm card-refresh" onClick={() => this.getAllStats()} />; + const refreshFullButton = ( + <button + type="button" + className="btn btn-outline-primary btn-sm" + onClick={() => this.getAllStats()} + > + <Trans>refresh_statics</Trans> + </button> + ); + const refreshButton = ( + <button + type="button" + className="btn btn-icon btn-outline-primary btn-sm" + onClick={() => this.getAllStats()} + > + <svg className="icons"> + <use xlinkHref="#refresh" /> + </svg> + </button> + ); return ( <Fragment> diff --git a/client/src/components/Header/Header.css b/client/src/components/Header/Header.css index 35e8a3cc..759594ac 100644 --- a/client/src/components/Header/Header.css +++ b/client/src/components/Header/Header.css @@ -75,7 +75,11 @@ } .nav-version__value { + max-width: 110px; font-weight: 600; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } .nav-version__link { @@ -85,6 +89,11 @@ cursor: pointer; } +.nav-version__text { + display: flex; + justify-content: flex-end; +} + .header-brand-img { height: 32px; } diff --git a/client/src/components/Header/Version.js b/client/src/components/Header/Version.js index be2158e9..6ac4f1ab 100644 --- a/client/src/components/Header/Version.js +++ b/client/src/components/Header/Version.js @@ -4,12 +4,26 @@ import { Trans, withNamespaces } from 'react-i18next'; import { getDnsAddress } from '../../helpers/helpers'; -function Version(props) { - const { dnsVersion, dnsAddresses, dnsPort } = props; +const Version = (props) => { + const { + dnsVersion, dnsAddresses, dnsPort, processingVersion, t, + } = props; + return ( <div className="nav-version"> <div className="nav-version__text"> - <Trans>version</Trans>: <span className="nav-version__value">{dnsVersion}</span> + <Trans>version</Trans>: <span className="nav-version__value" title={dnsVersion}>{dnsVersion}</span> + <button + type="button" + className="btn btn-icon btn-icon-sm btn-outline-primary btn-sm ml-2" + onClick={() => props.getVersion(true)} + disabled={processingVersion} + title={t('check_updates_now')} + > + <svg className="icons"> + <use xlinkHref="#refresh" /> + </svg> + </button> </div> <div className="nav-version__link"> <div className="popover__trigger popover__trigger--address"> @@ -17,20 +31,23 @@ function Version(props) { </div> <div className="popover__body popover__body--address"> <div className="popover__list"> - {dnsAddresses - .map(ip => <li key={ip}>{getDnsAddress(ip, dnsPort)}</li>) - } + {dnsAddresses.map(ip => ( + <li key={ip}>{getDnsAddress(ip, dnsPort)}</li> + ))} </div> </div> </div> </div> ); -} +}; Version.propTypes = { dnsVersion: PropTypes.string.isRequired, dnsAddresses: PropTypes.array.isRequired, dnsPort: PropTypes.number.isRequired, + getVersion: PropTypes.func.isRequired, + processingVersion: PropTypes.bool.isRequired, + t: PropTypes.func.isRequired, }; export default withNamespaces()(Version); diff --git a/client/src/components/Header/index.js b/client/src/components/Header/index.js index e2d47fe6..07e64241 100644 --- a/client/src/components/Header/index.js +++ b/client/src/components/Header/index.js @@ -23,7 +23,7 @@ class Header extends Component { }; render() { - const { dashboard } = this.props; + const { dashboard, getVersion, location } = this.props; const { isMenuOpen } = this.state; const badgeClass = classnames({ 'badge dns-status': true, @@ -51,7 +51,7 @@ class Header extends Component { </div> </div> <Menu - location={this.props.location} + location={location} isMenuOpen={isMenuOpen} toggleMenuOpen={this.toggleMenuOpen} closeMenu={this.closeMenu} @@ -59,7 +59,8 @@ class Header extends Component { {!dashboard.processing && <div className="col col-sm-6 col-lg-3"> <Version - { ...this.props.dashboard } + { ...dashboard } + getVersion={getVersion} /> </div> } @@ -71,8 +72,9 @@ class Header extends Component { } Header.propTypes = { - dashboard: PropTypes.object, - location: PropTypes.object, + dashboard: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, + getVersion: PropTypes.func.isRequired, }; export default withNamespaces()(Header); diff --git a/client/src/components/Settings/Settings.css b/client/src/components/Settings/Settings.css index 7e410a0c..48acf4eb 100644 --- a/client/src/components/Settings/Settings.css +++ b/client/src/components/Settings/Settings.css @@ -88,3 +88,10 @@ width: 30px; height: 30px; } + +.btn-icon-sm { + width: 23px; + height: 23px; + min-width: 23px; + padding: 5px; +} diff --git a/client/src/components/ui/Card.css b/client/src/components/ui/Card.css index 33b69c2d..6794a791 100644 --- a/client/src/components/ui/Card.css +++ b/client/src/components/ui/Card.css @@ -33,21 +33,6 @@ text-align: center; } -.card-refresh { - height: 26px; - width: 26px; - background-size: 14px; - background-position: center; - background-repeat: no-repeat; - background-image: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI0IiBzdHJva2U9IiM0NjdmY2YiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMjMgNHY2aC02Ii8+PHBhdGggZD0ibTEgMjB2LTZoNiIvPjxwYXRoIGQ9Im0zLjUxIDlhOSA5IDAgMCAxIDE0Ljg1LTMuMzZsNC42NCA0LjM2bS0yMiA0IDQuNjQgNC4zNmE5IDkgMCAwIDAgMTQuODUtMy4zNiIvPjwvc3ZnPg=="); -} - -.card-refresh:hover, -.card-refresh:not(:disabled):not(.disabled):active, -.card-refresh:focus:active { - background-image: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI0IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMjMgNHY2aC02Ii8+PHBhdGggZD0ibTEgMjB2LTZoNiIvPjxwYXRoIGQ9Im0zLjUxIDlhOSA5IDAgMCAxIDE0Ljg1LTMuMzZsNC42NCA0LjM2bS0yMiA0IDQuNjQgNC4zNmE5IDkgMCAwIDAgMTQuODUtMy4zNiIvPjwvc3ZnPg=="); -} - .card-title-stats { font-size: 13px; color: #9aa0ac; diff --git a/client/src/components/ui/Icons.js b/client/src/components/ui/Icons.js index 58a5af9f..92a9efa4 100644 --- a/client/src/components/ui/Icons.js +++ b/client/src/components/ui/Icons.js @@ -55,6 +55,10 @@ const Icons = () => ( <symbol id="settings" viewBox="0 0 24 24" stroke="currentColor" fill="none" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2"> <circle cx="12" cy="12" r="3"/><path d="m19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1 -2.83 0l-.06-.06a1.65 1.65 0 0 0 -1.82-.33 1.65 1.65 0 0 0 -1 1.51v.17a2 2 0 0 1 -2 2 2 2 0 0 1 -2-2v-.09a1.65 1.65 0 0 0 -1.08-1.51 1.65 1.65 0 0 0 -1.82.33l-.06.06a2 2 0 0 1 -2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0 -1.51-1h-.17a2 2 0 0 1 -2-2 2 2 0 0 1 2-2h.09a1.65 1.65 0 0 0 1.51-1.08 1.65 1.65 0 0 0 -.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33h.08a1.65 1.65 0 0 0 1-1.51v-.17a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0 -.33 1.82v.08a1.65 1.65 0 0 0 1.51 1h.17a2 2 0 0 1 2 2 2 2 0 0 1 -2 2h-.09a1.65 1.65 0 0 0 -1.51 1z"/> </symbol> + + <symbol id="refresh" viewBox="0 0 24 24" stroke="currentColor" fill="none" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2"> + <path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/> + </symbol> </svg> ); diff --git a/client/src/reducers/index.js b/client/src/reducers/index.js index 17d82608..94301e25 100644 --- a/client/src/reducers/index.js +++ b/client/src/reducers/index.js @@ -137,6 +137,7 @@ const dashboard = handleActions({ newVersion, canAutoUpdate, isUpdateAvailable: true, + processingVersion: false, }; return newState; }