From 6c70d8ca37e1129f0aae1338159366b9950ee5ac Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Wed, 12 Sep 2018 12:58:55 +0300 Subject: [PATCH 1/6] Add alert on failed requests --- client/package-lock.json | 5 +++++ client/package.json | 1 + client/src/actions/index.js | 20 ++++++++++++++++---- client/src/components/App/index.js | 2 ++ client/src/components/ui/Alertify.css | 9 +++++++++ 5 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 client/src/components/ui/Alertify.css diff --git a/client/package-lock.json b/client/package-lock.json index 3309c809..26ca1857 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -324,6 +324,11 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, + "alertifyjs": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/alertifyjs/-/alertifyjs-1.11.1.tgz", + "integrity": "sha512-8rw5zvMlg0Idltq15OOU9tGabYVA/I8JTNIM5ICUXqvrdPb7cfl+sSkTv9pDc6bbB8p9L85GtmOG7SUSv+bugQ==" + }, "align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", diff --git a/client/package.json b/client/package.json index 19260f52..4b43075b 100644 --- a/client/package.json +++ b/client/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@nivo/line": "^0.42.1", + "alertifyjs": "^1.11.1", "axios": "^0.18.0", "classnames": "^2.2.6", "date-fns": "^1.29.0", diff --git a/client/src/actions/index.js b/client/src/actions/index.js index daa1cc49..5b693b92 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -1,5 +1,6 @@ import { createAction } from 'redux-actions'; import round from 'lodash/round'; +import alertify from 'alertifyjs'; import { normalizeHistory, normalizeFilteringStatus, normalizeLogs } from '../helpers/helpers'; import Api from '../api/Api'; @@ -119,6 +120,7 @@ export const disableDns = () => async (dispatch) => { dispatch(disableDnsSuccess()); } catch (error) { console.error(error); + alertify.error(`Failed to disable DNS with status code ${error.response.status}`); dispatch(disableDnsFailure()); } }; @@ -154,8 +156,13 @@ export const getTopStats = () => async (dispatch, getState) => { const state = getState(); const timer = setInterval(async () => { if (state.dashboard.isCoreRunning) { - const stats = await apiClient.getGlobalStatsTop(); - dispatch(getTopStatsSuccess(stats)); + try { + const stats = await apiClient.getGlobalStatsTop(); + dispatch(getTopStatsSuccess(stats)); + } catch (error) { + alertify.error(`Failed to load statistics with status code ${error.response.status}`); + dispatch(getTopStatsFailure()); + } clearInterval(timer); } }, 100); @@ -175,8 +182,13 @@ export const getLogs = () => async (dispatch, getState) => { const state = getState(); const timer = setInterval(async () => { if (state.dashboard.isCoreRunning) { - const logs = normalizeLogs(await apiClient.getQueryLog()); - dispatch(getLogsSuccess(logs)); + try { + const logs = normalizeLogs(await apiClient.getQueryLog()); + dispatch(getLogsSuccess(logs)); + } catch (error) { + alertify.error(`Failed to load query log with status code ${error.response.status}`); + dispatch(getLogsFailure()); + } clearInterval(timer); } }, 100); diff --git a/client/src/components/App/index.js b/client/src/components/App/index.js index 7bdad801..fcb31887 100644 --- a/client/src/components/App/index.js +++ b/client/src/components/App/index.js @@ -3,8 +3,10 @@ import { HashRouter, Route } from 'react-router-dom'; import PropTypes from 'prop-types'; import 'react-table/react-table.css'; +import 'alertifyjs/build/css/alertify.min.css'; import '../ui/Tabler.css'; import '../ui/ReactTable.css'; +import '../ui/Alertify.css'; import './index.css'; import Header from '../../containers/Header'; diff --git a/client/src/components/ui/Alertify.css b/client/src/components/ui/Alertify.css new file mode 100644 index 00000000..321a9b34 --- /dev/null +++ b/client/src/components/ui/Alertify.css @@ -0,0 +1,9 @@ +.alertify-notifier .ajs-message { + width: 280px; + font-weight: 600; + color: #fff; +} + +.alertify-notifier .ajs-message.ajs-error { + background-color: rgba(236, 53, 53, 0.76); +} From 9258fada475b984f92ef58409db7f35e96dd8fff Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Wed, 12 Sep 2018 15:38:54 +0300 Subject: [PATCH 2/6] Fix clear interval Closes #315 --- client/src/actions/index.js | 54 +++++++++++++++---------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/client/src/actions/index.js b/client/src/actions/index.js index 5b693b92..7905ffb1 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -152,24 +152,19 @@ export const getTopStatsSuccess = createAction('GET_TOP_STATS_SUCCESS'); export const getTopStats = () => async (dispatch, getState) => { dispatch(getTopStatsRequest()); - try { + const timer = setInterval(async () => { const state = getState(); - const timer = setInterval(async () => { - if (state.dashboard.isCoreRunning) { - try { - const stats = await apiClient.getGlobalStatsTop(); - dispatch(getTopStatsSuccess(stats)); - } catch (error) { - alertify.error(`Failed to load statistics with status code ${error.response.status}`); - dispatch(getTopStatsFailure()); - } - clearInterval(timer); + if (state.dashboard.isCoreRunning) { + clearInterval(timer); + try { + const stats = await apiClient.getGlobalStatsTop(); + dispatch(getTopStatsSuccess(stats)); + } catch (error) { + alertify.error(`Failed to load statistics with status code ${error.response.status}`); + dispatch(getTopStatsFailure()); } - }, 100); - } catch (error) { - console.error(error); - dispatch(getTopStatsFailure()); - } + } + }, 100); }; export const getLogsRequest = createAction('GET_LOGS_REQUEST'); @@ -178,24 +173,19 @@ export const getLogsSuccess = createAction('GET_LOGS_SUCCESS'); export const getLogs = () => async (dispatch, getState) => { dispatch(getLogsRequest()); - try { + const timer = setInterval(async () => { const state = getState(); - const timer = setInterval(async () => { - if (state.dashboard.isCoreRunning) { - try { - const logs = normalizeLogs(await apiClient.getQueryLog()); - dispatch(getLogsSuccess(logs)); - } catch (error) { - alertify.error(`Failed to load query log with status code ${error.response.status}`); - dispatch(getLogsFailure()); - } - clearInterval(timer); + if (state.dashboard.isCoreRunning) { + clearInterval(timer); + try { + const logs = normalizeLogs(await apiClient.getQueryLog()); + dispatch(getLogsSuccess(logs)); + } catch (error) { + alertify.error(`Failed to load query log with status code ${error.response.status}`); + dispatch(getLogsFailure()); } - }, 100); - } catch (error) { - console.error(error); - dispatch(getLogsFailure()); - } + } + }, 100); }; export const toggleLogStatusRequest = createAction('TOGGLE_LOGS_REQUEST'); From 828bb40084963436aeb2c39fa2f5c75a8b17e983 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Fri, 14 Sep 2018 15:37:35 +0300 Subject: [PATCH 3/6] Show toast on failed request --- client/package-lock.json | 26 ++++++++-- client/package.json | 3 +- client/src/actions/index.js | 33 ++++++++++--- client/src/api/Api.js | 16 ++++--- client/src/components/App/index.js | 5 +- client/src/components/Dashboard/index.js | 2 - client/src/components/Toasts/Toast.css | 60 ++++++++++++++++++++++++ client/src/components/Toasts/Toast.js | 36 ++++++++++++++ client/src/components/Toasts/index.js | 42 +++++++++++++++++ client/src/components/ui/Alertify.css | 9 ---- client/src/reducers/index.js | 30 ++++++++++++ 11 files changed, 230 insertions(+), 32 deletions(-) create mode 100644 client/src/components/Toasts/Toast.css create mode 100644 client/src/components/Toasts/Toast.js create mode 100644 client/src/components/Toasts/index.js delete mode 100644 client/src/components/ui/Alertify.css diff --git a/client/package-lock.json b/client/package-lock.json index 26ca1857..a40c8624 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -324,11 +324,6 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, - "alertifyjs": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/alertifyjs/-/alertifyjs-1.11.1.tgz", - "integrity": "sha512-8rw5zvMlg0Idltq15OOU9tGabYVA/I8JTNIM5ICUXqvrdPb7cfl+sSkTv9pDc6bbB8p9L85GtmOG7SUSv+bugQ==" - }, "align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", @@ -3854,6 +3849,11 @@ } } }, + "dom-helpers": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.3.1.tgz", + "integrity": "sha512-2Sm+JaYn74OiTM2wHvxJOo3roiq/h25Yi69Fqk269cNUwIXsCvATB6CRSFC9Am/20G2b28hGv/+7NiWydIrPvg==" + }, "dom-serializer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", @@ -9053,6 +9053,11 @@ "dev": true, "optional": true }, + "nanoid": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-1.2.3.tgz", + "integrity": "sha512-BAnxAdaihzMoszwhqRy8FPOX+dijs7esUEUYTIQ1KsOSKmCVNYnitAMmBDFxYzA6VQYvuUKw7o2K1AcMBTGzIg==" + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -12953,6 +12958,17 @@ "prop-types": "^15.5.6" } }, + "react-transition-group": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.4.0.tgz", + "integrity": "sha512-Xv5d55NkJUxUzLCImGSanK8Cl/30sgpOEMGc5m86t8+kZwrPxPCPcFqyx83kkr+5Lz5gs6djuvE5By+gce+VjA==", + "requires": { + "dom-helpers": "^3.3.1", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/client/package.json b/client/package.json index 4b43075b..ce8e436d 100644 --- a/client/package.json +++ b/client/package.json @@ -10,12 +10,12 @@ }, "dependencies": { "@nivo/line": "^0.42.1", - "alertifyjs": "^1.11.1", "axios": "^0.18.0", "classnames": "^2.2.6", "date-fns": "^1.29.0", "file-saver": "^1.3.8", "lodash": "^4.17.10", + "nanoid": "^1.2.3", "prop-types": "^15.6.1", "react": "^16.4.0", "react-click-outside": "^3.0.1", @@ -24,6 +24,7 @@ "react-redux": "^5.0.7", "react-router-dom": "^4.2.2", "react-table": "^6.8.6", + "react-transition-group": "^2.4.0", "redux": "^4.0.0", "redux-actions": "^2.4.0", "redux-thunk": "^2.3.0", diff --git a/client/src/actions/index.js b/client/src/actions/index.js index 7905ffb1..de5b2c3b 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -1,12 +1,15 @@ import { createAction } from 'redux-actions'; import round from 'lodash/round'; -import alertify from 'alertifyjs'; import { normalizeHistory, normalizeFilteringStatus, normalizeLogs } from '../helpers/helpers'; import Api from '../api/Api'; const apiClient = new Api(); +export const addErrorToast = createAction('ADD_ERROR_TOAST'); +export const addSuccessToast = createAction('ADD_SUCCESS_TOAST'); +export const removeToast = createAction('REMOVE_TOAST'); + export const toggleSettingStatus = createAction('SETTING_STATUS_TOGGLE'); export const showSettingsFailure = createAction('SETTINGS_FAILURE_SHOW'); @@ -75,6 +78,7 @@ export const initSettings = settingsList => async (dispatch) => { dispatch(initSettingsSuccess({ settingsList: newSettingsList })); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(initSettingsFailure()); } }; @@ -90,6 +94,7 @@ export const getDnsStatus = () => async (dispatch) => { dispatch(dnsStatusSuccess(dnsStatus)); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(initSettingsFailure()); } }; @@ -105,6 +110,7 @@ export const enableDns = () => async (dispatch) => { dispatch(enableDnsSuccess()); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(enableDnsFailure()); } }; @@ -120,8 +126,8 @@ export const disableDns = () => async (dispatch) => { dispatch(disableDnsSuccess()); } catch (error) { console.error(error); - alertify.error(`Failed to disable DNS with status code ${error.response.status}`); - dispatch(disableDnsFailure()); + dispatch(disableDnsFailure(error)); + dispatch(addErrorToast({ error })); } }; @@ -142,6 +148,7 @@ export const getStats = () => async (dispatch) => { dispatch(getStatsSuccess(processedStats)); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(getStatsFailure()); } }; @@ -160,8 +167,9 @@ export const getTopStats = () => async (dispatch, getState) => { const stats = await apiClient.getGlobalStatsTop(); dispatch(getTopStatsSuccess(stats)); } catch (error) { - alertify.error(`Failed to load statistics with status code ${error.response.status}`); - dispatch(getTopStatsFailure()); + console.error(error); + dispatch(addErrorToast({ error })); + dispatch(getTopStatsFailure(error)); } } }, 100); @@ -181,8 +189,9 @@ export const getLogs = () => async (dispatch, getState) => { const logs = normalizeLogs(await apiClient.getQueryLog()); dispatch(getLogsSuccess(logs)); } catch (error) { - alertify.error(`Failed to load query log with status code ${error.response.status}`); - dispatch(getLogsFailure()); + console.error(error); + dispatch(addErrorToast({ error })); + dispatch(getLogsFailure(error)); } } }, 100); @@ -205,6 +214,7 @@ export const toggleLogStatus = queryLogEnabled => async (dispatch) => { dispatch(toggleLogStatusSuccess()); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(toggleLogStatusFailure()); } }; @@ -220,6 +230,7 @@ export const setRules = rules => async (dispatch) => { dispatch(setRulesSuccess()); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(setRulesFailure()); } }; @@ -235,6 +246,7 @@ export const getFilteringStatus = () => async (dispatch) => { dispatch(getFilteringStatusSuccess({ status: normalizeFilteringStatus(status) })); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(getFilteringStatusFailure()); } }; @@ -261,6 +273,7 @@ export const toggleFilterStatus = url => async (dispatch, getState) => { dispatch(getFilteringStatus()); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(toggleFilterFailure()); } }; @@ -277,6 +290,7 @@ export const refreshFilters = () => async (dispatch) => { dispatch(getFilteringStatus()); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(refreshFiltersFailure()); } }; @@ -295,6 +309,7 @@ export const getStatsHistory = () => async (dispatch) => { dispatch(getStatsHistorySuccess(normalizedHistory)); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(getStatsHistoryFailure()); } }; @@ -311,6 +326,7 @@ export const addFilter = url => async (dispatch) => { dispatch(getFilteringStatus()); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(addFilterFailure()); } }; @@ -328,6 +344,7 @@ export const removeFilter = url => async (dispatch) => { dispatch(getFilteringStatus()); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(removeFilterFailure()); } }; @@ -347,6 +364,7 @@ export const downloadQueryLog = () => async (dispatch) => { dispatch(downloadQueryLogSuccess()); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(downloadQueryLogFailure()); } return data; @@ -364,6 +382,7 @@ export const setUpstream = url => async (dispatch) => { dispatch(setUpstreamSuccess()); } catch (error) { console.error(error); + dispatch(addErrorToast({ error })); dispatch(setUpstreamFailure()); } }; diff --git a/client/src/api/Api.js b/client/src/api/Api.js index 1ba54271..e09ed797 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -6,12 +6,16 @@ export default class Api { baseUrl = 'control'; async makeRequest(path, method = 'POST', config) { - const response = await axios({ - url: `${this.baseUrl}/${path}`, - method, - ...config, - }); - return response.data; + try { + const response = await axios({ + url: `${this.baseUrl}/${path}`, + method, + ...config, + }); + return response.data; + } catch (error) { + throw new Error(`${this.baseUrl}/${path} | ${error.response.data} | ${error.response.status}`); + } } // Global methods diff --git a/client/src/components/App/index.js b/client/src/components/App/index.js index fcb31887..1b48620c 100644 --- a/client/src/components/App/index.js +++ b/client/src/components/App/index.js @@ -3,10 +3,8 @@ import { HashRouter, Route } from 'react-router-dom'; import PropTypes from 'prop-types'; import 'react-table/react-table.css'; -import 'alertifyjs/build/css/alertify.min.css'; import '../ui/Tabler.css'; import '../ui/ReactTable.css'; -import '../ui/Alertify.css'; import './index.css'; import Header from '../../containers/Header'; @@ -15,6 +13,7 @@ import Settings from '../../containers/Settings'; import Filters from '../../containers/Filters'; import Logs from '../../containers/Logs'; import Footer from '../ui/Footer'; +import Toasts from '../Toasts'; import Status from '../ui/Status'; @@ -51,6 +50,7 @@ class App extends Component { }