+ client: handle update
This commit is contained in:
parent
068072bc5a
commit
cb3f7f2834
|
@ -260,5 +260,7 @@
|
||||||
"dns_addresses": "DNS addresses",
|
"dns_addresses": "DNS addresses",
|
||||||
"down": "Down",
|
"down": "Down",
|
||||||
"fix": "Fix",
|
"fix": "Fix",
|
||||||
"dns_providers": "Here is a <0>list of known DNS providers</0> to choose from."
|
"dns_providers": "Here is a <0>list of known DNS providers</0> to choose from.",
|
||||||
|
"update_now": "Update now",
|
||||||
|
"processing_update": "Please wait, AdGuard Home is being updated"
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ import { t } from 'i18next';
|
||||||
import { showLoading, hideLoading } from 'react-redux-loading-bar';
|
import { showLoading, hideLoading } from 'react-redux-loading-bar';
|
||||||
|
|
||||||
import { normalizeHistory, normalizeFilteringStatus, normalizeLogs, normalizeTextarea } from '../helpers/helpers';
|
import { normalizeHistory, normalizeFilteringStatus, normalizeLogs, normalizeTextarea } from '../helpers/helpers';
|
||||||
import { SETTINGS_NAMES } from '../helpers/constants';
|
import { SETTINGS_NAMES, CHECK_TIMEOUT } from '../helpers/constants';
|
||||||
import Api from '../api/Api';
|
import Api from '../api/Api';
|
||||||
|
|
||||||
const apiClient = new Api();
|
const apiClient = new Api();
|
||||||
|
@ -154,6 +154,29 @@ export const getVersion = () => async (dispatch) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getUpdateRequest = createAction('GET_UPDATE_REQUEST');
|
||||||
|
export const getUpdateFailure = createAction('GET_UPDATE_FAILURE');
|
||||||
|
export const getUpdateSuccess = createAction('GET_UPDATE_SUCCESS');
|
||||||
|
|
||||||
|
export const getUpdate = () => async (dispatch) => {
|
||||||
|
dispatch(getUpdateRequest());
|
||||||
|
try {
|
||||||
|
await apiClient.getUpdate();
|
||||||
|
|
||||||
|
const timer = setInterval(async () => {
|
||||||
|
const dnsStatus = await apiClient.getGlobalStatus();
|
||||||
|
if (dnsStatus) {
|
||||||
|
clearInterval(timer);
|
||||||
|
dispatch(getUpdateSuccess());
|
||||||
|
window.location.reload(true);
|
||||||
|
}
|
||||||
|
}, CHECK_TIMEOUT);
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(addErrorToast({ error }));
|
||||||
|
dispatch(getUpdateFailure());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const getClientsRequest = createAction('GET_CLIENTS_REQUEST');
|
export const getClientsRequest = createAction('GET_CLIENTS_REQUEST');
|
||||||
export const getClientsFailure = createAction('GET_CLIENTS_FAILURE');
|
export const getClientsFailure = createAction('GET_CLIENTS_FAILURE');
|
||||||
export const getClientsSuccess = createAction('GET_CLIENTS_SUCCESS');
|
export const getClientsSuccess = createAction('GET_CLIENTS_SUCCESS');
|
||||||
|
|
|
@ -40,6 +40,8 @@ export default class Api {
|
||||||
GLOBAL_ENABLE_PROTECTION = { path: 'enable_protection', method: 'POST' };
|
GLOBAL_ENABLE_PROTECTION = { path: 'enable_protection', method: 'POST' };
|
||||||
GLOBAL_DISABLE_PROTECTION = { path: 'disable_protection', method: 'POST' };
|
GLOBAL_DISABLE_PROTECTION = { path: 'disable_protection', method: 'POST' };
|
||||||
GLOBAL_CLIENTS = { path: 'clients', method: 'GET' }
|
GLOBAL_CLIENTS = { path: 'clients', method: 'GET' }
|
||||||
|
GLOBAL_CLIENTS = { path: 'clients', method: 'GET' };
|
||||||
|
GLOBAL_UPDATE = { path: 'update', method: 'POST' };
|
||||||
|
|
||||||
restartGlobalFiltering() {
|
restartGlobalFiltering() {
|
||||||
const { path, method } = this.GLOBAL_RESTART;
|
const { path, method } = this.GLOBAL_RESTART;
|
||||||
|
@ -145,6 +147,11 @@ export default class Api {
|
||||||
return this.makeRequest(path, method);
|
return this.makeRequest(path, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getUpdate() {
|
||||||
|
const { path, method } = this.GLOBAL_UPDATE;
|
||||||
|
return this.makeRequest(path, method);
|
||||||
|
}
|
||||||
|
|
||||||
// Filtering
|
// Filtering
|
||||||
FILTERING_STATUS = { path: 'filtering/status', method: 'GET' };
|
FILTERING_STATUS = { path: 'filtering/status', method: 'GET' };
|
||||||
FILTERING_ENABLE = { path: 'filtering/enable', method: 'POST' };
|
FILTERING_ENABLE = { path: 'filtering/enable', method: 'POST' };
|
||||||
|
|
|
@ -19,6 +19,7 @@ import Toasts from '../Toasts';
|
||||||
import Footer from '../ui/Footer';
|
import Footer from '../ui/Footer';
|
||||||
import Status from '../ui/Status';
|
import Status from '../ui/Status';
|
||||||
import UpdateTopline from '../ui/UpdateTopline';
|
import UpdateTopline from '../ui/UpdateTopline';
|
||||||
|
import UpdateOverlay from '../ui/UpdateOverlay';
|
||||||
import EncryptionTopline from '../ui/EncryptionTopline';
|
import EncryptionTopline from '../ui/EncryptionTopline';
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
|
|
||||||
|
@ -37,6 +38,10 @@ class App extends Component {
|
||||||
this.props.enableDns();
|
this.props.enableDns();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleUpdate = () => {
|
||||||
|
this.props.getUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
setLanguage = () => {
|
setLanguage = () => {
|
||||||
const { processing, language } = this.props.dashboard;
|
const { processing, language } = this.props.dashboard;
|
||||||
|
|
||||||
|
@ -62,10 +67,16 @@ class App extends Component {
|
||||||
<HashRouter hashType='noslash'>
|
<HashRouter hashType='noslash'>
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{updateAvailable &&
|
{updateAvailable &&
|
||||||
<UpdateTopline
|
<Fragment>
|
||||||
url={dashboard.announcementUrl}
|
<UpdateTopline
|
||||||
version={dashboard.version}
|
url={dashboard.announcementUrl}
|
||||||
/>
|
version={dashboard.newVersion}
|
||||||
|
canAutoUpdate={dashboard.canAutoUpdate}
|
||||||
|
getUpdate={this.handleUpdate}
|
||||||
|
processingUpdate={dashboard.processingUpdate}
|
||||||
|
/>
|
||||||
|
<UpdateOverlay processingUpdate={dashboard.processingUpdate} />
|
||||||
|
</Fragment>
|
||||||
}
|
}
|
||||||
{!encryption.processing &&
|
{!encryption.processing &&
|
||||||
<EncryptionTopline notAfter={encryption.not_after} />
|
<EncryptionTopline notAfter={encryption.not_after} />
|
||||||
|
@ -100,6 +111,7 @@ class App extends Component {
|
||||||
|
|
||||||
App.propTypes = {
|
App.propTypes = {
|
||||||
getDnsStatus: PropTypes.func,
|
getDnsStatus: PropTypes.func,
|
||||||
|
getUpdate: PropTypes.func,
|
||||||
enableDns: PropTypes.func,
|
enableDns: PropTypes.func,
|
||||||
dashboard: PropTypes.object,
|
dashboard: PropTypes.object,
|
||||||
isCoreRunning: PropTypes.bool,
|
isCoreRunning: PropTypes.bool,
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
.overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 110;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay--visible {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay__loading {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2047.6%2047.6%22%20height%3D%22100%25%22%20width%3D%22100%25%22%3E%3Cpath%20opacity%3D%22.235%22%20fill%3D%22%23979797%22%20d%3D%22M44.4%2011.9l-5.2%203c1.5%202.6%202.4%205.6%202.4%208.9%200%209.8-8%2017.8-17.8%2017.8-6.6%200-12.3-3.6-15.4-8.9l-5.2%203C7.3%2042.8%2015%2047.6%2023.8%2047.6c13.1%200%2023.8-10.7%2023.8-23.8%200-4.3-1.2-8.4-3.2-11.9z%22%2F%3E%3Cpath%20fill%3D%22%2366b574%22%20d%3D%22M3.2%2035.7C0%2030.2-.8%2023.8.8%2017.6%202.5%2011.5%206.4%206.4%2011.9%203.2%2017.4%200%2023.8-.8%2030%20.8c6.1%201.6%2011.3%205.6%2014.4%2011.1l-5.2%203c-2.4-4.1-6.2-7.1-10.8-8.3C23.8%205.4%2019%206%2014.9%208.4s-7.1%206.2-8.3%2010.8c-1.2%204.6-.6%209.4%201.8%2013.5l-5.2%203z%22%2F%3E%3C%2Fsvg%3E");
|
||||||
|
will-change: transform;
|
||||||
|
animation: clockwise 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes clockwise {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Trans, withNamespaces } from 'react-i18next';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
import './Overlay.css';
|
||||||
|
|
||||||
|
const UpdateOverlay = (props) => {
|
||||||
|
const overlayClass = classnames({
|
||||||
|
overlay: true,
|
||||||
|
'overlay--visible': props.processingUpdate,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={overlayClass}>
|
||||||
|
<div className="overlay__loading"></div>
|
||||||
|
<Trans>processing_update</Trans>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
UpdateOverlay.propTypes = {
|
||||||
|
processingUpdate: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withNamespaces()(UpdateOverlay);
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Trans, withNamespaces } from 'react-i18next';
|
import { Trans, withNamespaces } from 'react-i18next';
|
||||||
|
|
||||||
|
@ -6,22 +6,37 @@ import Topline from './Topline';
|
||||||
|
|
||||||
const UpdateTopline = props => (
|
const UpdateTopline = props => (
|
||||||
<Topline type="info">
|
<Topline type="info">
|
||||||
<Trans
|
<Fragment>
|
||||||
values={{ version: props.version }}
|
<Trans
|
||||||
components={[
|
values={{ version: props.version }}
|
||||||
<a href={props.url} target="_blank" rel="noopener noreferrer" key="0">
|
components={[
|
||||||
Click here
|
<a href={props.url} target="_blank" rel="noopener noreferrer" key="0">
|
||||||
</a>,
|
Click here
|
||||||
]}
|
</a>,
|
||||||
>
|
]}
|
||||||
update_announcement
|
>
|
||||||
</Trans>
|
update_announcement
|
||||||
|
</Trans>
|
||||||
|
{props.canAutoUpdate &&
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-sm btn-primary ml-3"
|
||||||
|
onClick={props.getUpdate}
|
||||||
|
disabled={props.processingUpdate}
|
||||||
|
>
|
||||||
|
<Trans>update_now</Trans>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</Fragment>
|
||||||
</Topline>
|
</Topline>
|
||||||
);
|
);
|
||||||
|
|
||||||
UpdateTopline.propTypes = {
|
UpdateTopline.propTypes = {
|
||||||
version: PropTypes.string.isRequired,
|
version: PropTypes.string,
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
|
canAutoUpdate: PropTypes.bool,
|
||||||
|
getUpdate: PropTypes.func,
|
||||||
|
processingUpdate: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withNamespaces()(UpdateTopline);
|
export default withNamespaces()(UpdateTopline);
|
||||||
|
|
|
@ -126,12 +126,16 @@ const dashboard = handleActions({
|
||||||
const {
|
const {
|
||||||
version,
|
version,
|
||||||
announcement_url: announcementUrl,
|
announcement_url: announcementUrl,
|
||||||
|
new_version: newVersion,
|
||||||
|
can_autoupdate: canAutoUpdate,
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
const newState = {
|
const newState = {
|
||||||
...state,
|
...state,
|
||||||
version,
|
version,
|
||||||
announcementUrl,
|
announcementUrl,
|
||||||
|
newVersion,
|
||||||
|
canAutoUpdate,
|
||||||
isUpdateAvailable: true,
|
isUpdateAvailable: true,
|
||||||
};
|
};
|
||||||
return newState;
|
return newState;
|
||||||
|
@ -140,6 +144,13 @@ const dashboard = handleActions({
|
||||||
return state;
|
return state;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[actions.getUpdateRequest]: state => ({ ...state, processingUpdate: true }),
|
||||||
|
[actions.getUpdateFailure]: state => ({ ...state, processingUpdate: false }),
|
||||||
|
[actions.getUpdateSuccess]: (state) => {
|
||||||
|
const newState = { ...state, processingUpdate: false };
|
||||||
|
return newState;
|
||||||
|
},
|
||||||
|
|
||||||
[actions.getFilteringRequest]: state => ({ ...state, processingFiltering: true }),
|
[actions.getFilteringRequest]: state => ({ ...state, processingFiltering: true }),
|
||||||
[actions.getFilteringFailure]: state => ({ ...state, processingFiltering: false }),
|
[actions.getFilteringFailure]: state => ({ ...state, processingFiltering: false }),
|
||||||
[actions.getFilteringSuccess]: (state, { payload }) => {
|
[actions.getFilteringSuccess]: (state, { payload }) => {
|
||||||
|
@ -187,6 +198,7 @@ const dashboard = handleActions({
|
||||||
processingVersion: true,
|
processingVersion: true,
|
||||||
processingFiltering: true,
|
processingFiltering: true,
|
||||||
processingClients: true,
|
processingClients: true,
|
||||||
|
processingUpdate: false,
|
||||||
upstreamDns: '',
|
upstreamDns: '',
|
||||||
bootstrapDns: '',
|
bootstrapDns: '',
|
||||||
allServers: false,
|
allServers: false,
|
||||||
|
|
Loading…
Reference in New Issue