+ client: Update packages - Merge pull request #613 in DNS/adguard-home from fix/1597 to master

Close #1597

Squashed commit of the following:

commit 1eb89586dd71260e561420fe669abc8b56a506a1
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed May 20 14:54:10 2020 +0300

    Fix translation in install options

commit 1ebdc9ebfe12a609f978e47db6505c7095b10f7e
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed May 20 13:11:34 2020 +0300

    Remove commented code

commit 2a8302c65a2a3cf7b6b1596115d1153dac32a794
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue May 19 19:02:49 2020 +0300

    Update i18n packages, add development browserlist, downgrade eslint to match peerDepencancies version

commit 3fcf73fb14cd9da508522d1a300b66af24da95e5
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue May 19 17:30:37 2020 +0300

    Remove all unused dependencies

commit e761810e3e54e188ada41245bdce7414cd0f03e8
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue May 19 16:35:24 2020 +0300

    Remove unused dependencies

commit d89d27da6befcaabcdc12bf5e7e94cbb24140010
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue May 19 16:14:09 2020 +0300

    Update regular dependencies

commit d2dfd01233d059870d5173ffd748cf61a477936f
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue May 19 15:34:10 2020 +0300

    Update all dev dependancies

commit 02b6fb480e9d310039fbe9b7aae062a41128f070
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue May 19 14:14:44 2020 +0300

    Update all postcss packages

commit 5e1fa5f99ad75f77e5e429b28ee1ca0b5e65a9a0
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue May 19 12:45:02 2020 +0300

    Prevent git from converting linebreaks in .js files

commit 0b9b3b0dccd47cfa50c9531fb61729e6b5a04523
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue May 19 12:43:01 2020 +0300

    Prevent git from converting linebreaks in .js files

commit 18b7495e9ef7130b1ac4dbba84c54127d16c6350
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue May 19 12:24:47 2020 +0300

    Remove linebreak-style eslint rule

commit df893dec53adebb1d662fe805fab508fd4ed5e06
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Mon May 18 20:55:47 2020 +0300

    Add prop types

commit 36178ecfc5c7fa11a6ee08d7705ca8560941af40
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Mon May 18 18:52:07 2020 +0300

    Update eslint and babel, fix eslint warnings

commit f045b4a2e6b9b78f7e88e3b5d1419c29966a8230
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Mon May 18 16:45:49 2020 +0300

    Update css loading webpack rules

commit 247fa1ed548ef0706a03fdada8309c1454d191f8
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Sat May 16 16:13:49 2020 +0300

    Suppress linebreak-style eslint error for Windows

commit d6499aac507100d6918c849c06d739d80f2229f0
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Sat May 16 14:55:07 2020 +0300

    Suppress eslint exit code

commit ae2d6c614ea23a90d515168f8752e959298894ef
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Sat May 16 14:05:18 2020 +0300

    Edit css file warnings

commit 60675050f2a5baebc679fc05da7e033e5c740d90
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Sat May 16 13:10:26 2020 +0300

    Remove uglifyjs plugin

commit a27806434dd8672e71a26c7a2e810d77e5e229fa
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Sat May 16 01:29:17 2020 +0300

    Fix DefinePlugin value

commit 8f2966ca59195c2f70bca5072d20515d536f42a6
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Sat May 16 01:05:03 2020 +0300

    Update webpack
This commit is contained in:
Artem Baskal 2020-05-22 17:06:05 +03:00
parent 8b25a4886e
commit 6f3cd4e7eb
131 changed files with 7454 additions and 8907 deletions

16
client/.babelrc vendored Normal file
View File

@ -0,0 +1,16 @@
{
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
],
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-object-rest-spread"
]
}

1
client/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.js text eol=lf

14355
client/package-lock.json generated vendored

File diff suppressed because it is too large Load Diff

166
client/package.json vendored
View File

@ -1,81 +1,89 @@
{ {
"name": "dashboard", "name": "dashboard",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"build-dev": "cross-env NODE_ENV=development webpack --config webpack.dev.js", "build-dev": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js",
"watch": "cross-env NODE_ENV=development webpack --config webpack.dev.js --watch", "watch": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js --watch",
"build-prod": "cross-env NODE_ENV=production webpack --config webpack.prod.js", "build-prod": "cross-env BUILD_ENV=prod webpack --config webpack.prod.js",
"lint": "eslint client/" "lint": "eslint src"
}, },
"dependencies": { "dependencies": {
"@nivo/line": "^0.49.1", "@nivo/line": "^0.49.1",
"axios": "^0.19.0", "axios": "^0.19.2",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"date-fns": "^1.29.0", "date-fns": "^1.29.0",
"i18next": "^12.0.0", "i18next": "^19.4.4",
"i18next-browser-languagedetector": "^2.2.3", "i18next-browser-languagedetector": "^4.2.0",
"lodash": "^4.17.15", "lodash": "^4.17.15",
"nanoid": "^1.2.3", "nanoid": "^3.1.9",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react": "^16.4.0", "react": "^16.13.1",
"react-click-outside": "^3.0.1", "react-click-outside": "^3.0.1",
"react-dom": "^16.4.0", "react-dom": "^16.13.1",
"react-i18next": "^8.2.0", "react-i18next": "^11.4.0",
"react-modal": "^3.4.5", "react-modal": "^3.11.2",
"react-redux": "^5.0.7", "react-redux": "^7.2.0",
"react-redux-loading-bar": "^4.0.7", "react-redux-loading-bar": "^4.6.0",
"react-router-dom": "^4.2.2", "react-router-dom": "^5.2.0",
"react-router-hash-link": "^1.2.2", "react-router-hash-link": "^1.2.2",
"react-select": "^3.0.8", "react-select": "^3.1.0",
"react-table": "^6.10.3", "react-table": "^6.11.4",
"react-transition-group": "^2.4.0", "react-transition-group": "^4.4.1",
"redux": "^4.0.0", "redux": "^4.0.5",
"redux-actions": "^2.4.0", "redux-actions": "^2.6.5",
"redux-form": "^7.4.2", "redux-form": "^8.3.5",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"url-polyfill": "^1.1.7" "url-polyfill": "^1.1.9"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "^8.6.3", "@babel/core": "^7.9.6",
"babel-core": "6.26.0", "@babel/plugin-proposal-class-properties": "^7.8.3",
"babel-eslint": "^8.2.3", "@babel/plugin-proposal-object-rest-spread": "^7.9.6",
"babel-loader": "7.1.2", "@babel/plugin-transform-runtime": "^7.9.6",
"babel-plugin-transform-runtime": "^6.23.0", "@babel/preset-env": "^7.9.6",
"babel-preset-env": "^1.7.0", "@babel/preset-react": "^7.9.4",
"babel-preset-react": "^6.24.1", "autoprefixer": "^9.8.0",
"babel-preset-stage-2": "^6.24.1", "babel-eslint": "^10.1.0",
"babel-runtime": "6.26.0", "babel-loader": "^8.1.0",
"clean-webpack-plugin": "^0.1.19", "clean-webpack-plugin": "^3.0.0",
"compression-webpack-plugin": "^1.1.11", "copy-webpack-plugin": "^6.0.1",
"copy-webpack-plugin": "^4.6.0", "cross-env": "^7.0.2",
"cross-env": "^7.0.2", "css-loader": "^3.5.3",
"css-loader": "^2.1.1", "eslint": "^6.8.0",
"eslint": "^4.19.1", "eslint-config-airbnb": "^18.1.0",
"eslint-config-airbnb-base": "^12.1.0", "eslint-import-resolver-webpack": "^0.12.1",
"eslint-config-react-app": "^2.1.0", "eslint-loader": "^4.0.2",
"eslint-import-resolver-webpack": "^0.12.1", "eslint-plugin-import": "^2.20.2",
"eslint-loader": "1.9.0", "eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-import": "^2.12.0", "eslint-plugin-react": "^7.20.0",
"eslint-plugin-jsx-a11y": "5.1.1", "eslint-plugin-react-hooks": "^2.5.0",
"eslint-plugin-react": "^7.9.1", "file-loader": "6.0.0",
"extract-text-webpack-plugin": "^3.0.2", "html-webpack-plugin": "^4.3.0",
"file-loader": "1.1.5", "mini-css-extract-plugin": "^0.9.0",
"html-webpack-plugin": "^3.2.0", "path": "^0.12.7",
"postcss-flexbugs-fixes": "3.2.0", "postcss-flexbugs-fixes": "4.2.1",
"postcss-import": "^11.1.0", "postcss-loader": "^3.0.0",
"postcss-loader": "^2.1.5", "style-loader": "^1.2.1",
"postcss-mixins": "^6.2.0", "stylelint": "^13.5.0",
"postcss-preset-env": "^5.1.0", "stylelint-webpack-plugin": "2.0.0",
"postcss-svg": "^2.4.0", "url-loader": "^4.1.0",
"style-loader": "^0.21.0", "webpack": "^4.43.0",
"stylelint": "^9.10.1", "webpack-cli": "^3.3.11",
"stylelint-webpack-plugin": "0.10.4", "webpack-dev-server": "^3.11.0",
"svg-url-loader": "^2.3.2", "webpack-merge": "^4.2.2"
"uglifyjs-webpack-plugin": "^1.2.7", },
"url-loader": "^1.0.1", "browserslist": {
"webpack": "3.8.1", "development": [
"webpack-dev-server": "^3.1.14", "last 1 chrome version",
"webpack-merge": "^4.1.3" "last 1 firefox version",
} "last 1 safari version"
],
"production": [
">1%",
"last 4 versions",
"Firefox ESR",
"not ie < 9"
]
}
} }

View File

@ -1,10 +1,10 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import { t } from 'i18next'; import i18next from 'i18next';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index';
import { normalizeTextarea } from '../helpers/helpers'; import { normalizeTextarea } from '../helpers/helpers';
import { ACTION } from '../helpers/constants'; import { ACTION } from '../helpers/constants';
import { addErrorToast, addSuccessToast } from './toasts';
export const getAccessListRequest = createAction('GET_ACCESS_LIST_REQUEST'); export const getAccessListRequest = createAction('GET_ACCESS_LIST_REQUEST');
export const getAccessListFailure = createAction('GET_ACCESS_LIST_FAILURE'); export const getAccessListFailure = createAction('GET_ACCESS_LIST_FAILURE');
@ -25,7 +25,7 @@ export const setAccessListRequest = createAction('SET_ACCESS_LIST_REQUEST');
export const setAccessListFailure = createAction('SET_ACCESS_LIST_FAILURE'); export const setAccessListFailure = createAction('SET_ACCESS_LIST_FAILURE');
export const setAccessListSuccess = createAction('SET_ACCESS_LIST_SUCCESS'); export const setAccessListSuccess = createAction('SET_ACCESS_LIST_SUCCESS');
export const setAccessList = config => async (dispatch) => { export const setAccessList = (config) => async (dispatch) => {
dispatch(setAccessListRequest()); dispatch(setAccessListRequest());
try { try {
const { allowed_clients, disallowed_clients, blocked_hosts } = config; const { allowed_clients, disallowed_clients, blocked_hosts } = config;
@ -58,7 +58,7 @@ export const toggleClientBlock = (type, ip) => async (dispatch) => {
let updatedDisallowedClients = disallowed_clients || []; let updatedDisallowedClients = disallowed_clients || [];
if (type === ACTION.unblock && updatedDisallowedClients.includes(ip)) { if (type === ACTION.unblock && updatedDisallowedClients.includes(ip)) {
updatedDisallowedClients = updatedDisallowedClients.filter(client => client !== ip); updatedDisallowedClients = updatedDisallowedClients.filter((client) => client !== ip);
} else if (type === ACTION.block && !updatedDisallowedClients.includes(ip)) { } else if (type === ACTION.block && !updatedDisallowedClients.includes(ip)) {
updatedDisallowedClients.push(ip); updatedDisallowedClients.push(ip);
} }
@ -73,9 +73,9 @@ export const toggleClientBlock = (type, ip) => async (dispatch) => {
dispatch(toggleClientBlockSuccess(values)); dispatch(toggleClientBlockSuccess(values));
if (type === ACTION.unblock) { if (type === ACTION.unblock) {
dispatch(addSuccessToast(t('client_unblocked', { ip }))); dispatch(addSuccessToast(i18next.t('client_unblocked', { ip })));
} else if (type === ACTION.block) { } else if (type === ACTION.block) {
dispatch(addSuccessToast(t('client_blocked', { ip }))); dispatch(addSuccessToast(i18next.t('client_blocked', { ip })));
} }
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));

View File

@ -1,7 +1,8 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import { t } from 'i18next'; import i18next from 'i18next';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast, getClients } from './index'; import { getClients } from './index';
import { addErrorToast, addSuccessToast } from './toasts';
export const toggleClientModal = createAction('TOGGLE_CLIENT_MODAL'); export const toggleClientModal = createAction('TOGGLE_CLIENT_MODAL');
@ -9,13 +10,13 @@ export const addClientRequest = createAction('ADD_CLIENT_REQUEST');
export const addClientFailure = createAction('ADD_CLIENT_FAILURE'); export const addClientFailure = createAction('ADD_CLIENT_FAILURE');
export const addClientSuccess = createAction('ADD_CLIENT_SUCCESS'); export const addClientSuccess = createAction('ADD_CLIENT_SUCCESS');
export const addClient = config => async (dispatch) => { export const addClient = (config) => async (dispatch) => {
dispatch(addClientRequest()); dispatch(addClientRequest());
try { try {
await apiClient.addClient(config); await apiClient.addClient(config);
dispatch(addClientSuccess()); dispatch(addClientSuccess());
dispatch(toggleClientModal()); dispatch(toggleClientModal());
dispatch(addSuccessToast(t('client_added', { key: config.name }))); dispatch(addSuccessToast(i18next.t('client_added', { key: config.name })));
dispatch(getClients()); dispatch(getClients());
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));
@ -27,12 +28,12 @@ export const deleteClientRequest = createAction('DELETE_CLIENT_REQUEST');
export const deleteClientFailure = createAction('DELETE_CLIENT_FAILURE'); export const deleteClientFailure = createAction('DELETE_CLIENT_FAILURE');
export const deleteClientSuccess = createAction('DELETE_CLIENT_SUCCESS'); export const deleteClientSuccess = createAction('DELETE_CLIENT_SUCCESS');
export const deleteClient = config => async (dispatch) => { export const deleteClient = (config) => async (dispatch) => {
dispatch(deleteClientRequest()); dispatch(deleteClientRequest());
try { try {
await apiClient.deleteClient(config); await apiClient.deleteClient(config);
dispatch(deleteClientSuccess()); dispatch(deleteClientSuccess());
dispatch(addSuccessToast(t('client_deleted', { key: config.name }))); dispatch(addSuccessToast(i18next.t('client_deleted', { key: config.name })));
dispatch(getClients()); dispatch(getClients());
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));
@ -52,7 +53,7 @@ export const updateClient = (config, name) => async (dispatch) => {
await apiClient.updateClient(data); await apiClient.updateClient(data);
dispatch(updateClientSuccess()); dispatch(updateClientSuccess());
dispatch(toggleClientModal()); dispatch(toggleClientModal());
dispatch(addSuccessToast(t('client_updated', { key: name }))); dispatch(addSuccessToast(i18next.t('client_updated', { key: name })));
dispatch(getClients()); dispatch(getClients());
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));

View File

@ -1,8 +1,8 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index';
import { normalizeTextarea } from '../helpers/helpers'; import { normalizeTextarea } from '../helpers/helpers';
import { addErrorToast, addSuccessToast } from './toasts';
export const getDnsConfigRequest = createAction('GET_DNS_CONFIG_REQUEST'); export const getDnsConfigRequest = createAction('GET_DNS_CONFIG_REQUEST');
export const getDnsConfigFailure = createAction('GET_DNS_CONFIG_FAILURE'); export const getDnsConfigFailure = createAction('GET_DNS_CONFIG_FAILURE');
@ -23,7 +23,7 @@ export const setDnsConfigRequest = createAction('SET_DNS_CONFIG_REQUEST');
export const setDnsConfigFailure = createAction('SET_DNS_CONFIG_FAILURE'); export const setDnsConfigFailure = createAction('SET_DNS_CONFIG_FAILURE');
export const setDnsConfigSuccess = createAction('SET_DNS_CONFIG_SUCCESS'); export const setDnsConfigSuccess = createAction('SET_DNS_CONFIG_SUCCESS');
export const setDnsConfig = config => async (dispatch) => { export const setDnsConfig = (config) => async (dispatch) => {
dispatch(setDnsConfigRequest()); dispatch(setDnsConfigRequest());
try { try {
const data = { ...config }; const data = { ...config };

View File

@ -1,7 +1,7 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index';
import { redirectToCurrentProtocol } from '../helpers/helpers'; import { redirectToCurrentProtocol } from '../helpers/helpers';
import { addErrorToast, addSuccessToast } from './toasts';
export const getTlsStatusRequest = createAction('GET_TLS_STATUS_REQUEST'); export const getTlsStatusRequest = createAction('GET_TLS_STATUS_REQUEST');
export const getTlsStatusFailure = createAction('GET_TLS_STATUS_FAILURE'); export const getTlsStatusFailure = createAction('GET_TLS_STATUS_FAILURE');
@ -25,7 +25,7 @@ export const setTlsConfigRequest = createAction('SET_TLS_CONFIG_REQUEST');
export const setTlsConfigFailure = createAction('SET_TLS_CONFIG_FAILURE'); export const setTlsConfigFailure = createAction('SET_TLS_CONFIG_FAILURE');
export const setTlsConfigSuccess = createAction('SET_TLS_CONFIG_SUCCESS'); export const setTlsConfigSuccess = createAction('SET_TLS_CONFIG_SUCCESS');
export const setTlsConfig = config => async (dispatch, getState) => { export const setTlsConfig = (config) => async (dispatch, getState) => {
dispatch(setTlsConfigRequest()); dispatch(setTlsConfigRequest());
try { try {
const { httpPort } = getState().dashboard; const { httpPort } = getState().dashboard;
@ -51,7 +51,7 @@ export const validateTlsConfigRequest = createAction('VALIDATE_TLS_CONFIG_REQUES
export const validateTlsConfigFailure = createAction('VALIDATE_TLS_CONFIG_FAILURE'); export const validateTlsConfigFailure = createAction('VALIDATE_TLS_CONFIG_FAILURE');
export const validateTlsConfigSuccess = createAction('VALIDATE_TLS_CONFIG_SUCCESS'); export const validateTlsConfigSuccess = createAction('VALIDATE_TLS_CONFIG_SUCCESS');
export const validateTlsConfig = config => async (dispatch) => { export const validateTlsConfig = (config) => async (dispatch) => {
dispatch(validateTlsConfigRequest()); dispatch(validateTlsConfigRequest());
try { try {
const values = { ...config }; const values = { ...config };

View File

@ -1,10 +1,10 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import { showLoading, hideLoading } from 'react-redux-loading-bar'; import { showLoading, hideLoading } from 'react-redux-loading-bar';
import { t } from 'i18next'; import i18next from 'i18next';
import { normalizeFilteringStatus, normalizeRulesTextarea } from '../helpers/helpers'; import { normalizeFilteringStatus, normalizeRulesTextarea } from '../helpers/helpers';
import { addErrorToast, addSuccessToast } from './index';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './toasts';
export const toggleFilteringModal = createAction('FILTERING_MODAL_TOGGLE'); export const toggleFilteringModal = createAction('FILTERING_MODAL_TOGGLE');
export const handleRulesChange = createAction('HANDLE_RULES_CHANGE'); export const handleRulesChange = createAction('HANDLE_RULES_CHANGE');
@ -28,7 +28,7 @@ export const setRulesRequest = createAction('SET_RULES_REQUEST');
export const setRulesFailure = createAction('SET_RULES_FAILURE'); export const setRulesFailure = createAction('SET_RULES_FAILURE');
export const setRulesSuccess = createAction('SET_RULES_SUCCESS'); export const setRulesSuccess = createAction('SET_RULES_SUCCESS');
export const setRules = rules => async (dispatch) => { export const setRules = (rules) => async (dispatch) => {
dispatch(setRulesRequest()); dispatch(setRulesRequest());
try { try {
const normalizedRules = normalizeRulesTextarea(rules); const normalizedRules = normalizeRulesTextarea(rules);
@ -113,7 +113,7 @@ export const refreshFiltersRequest = createAction('FILTERING_REFRESH_REQUEST');
export const refreshFiltersFailure = createAction('FILTERING_REFRESH_FAILURE'); export const refreshFiltersFailure = createAction('FILTERING_REFRESH_FAILURE');
export const refreshFiltersSuccess = createAction('FILTERING_REFRESH_SUCCESS'); export const refreshFiltersSuccess = createAction('FILTERING_REFRESH_SUCCESS');
export const refreshFilters = config => async (dispatch) => { export const refreshFilters = (config) => async (dispatch) => {
dispatch(refreshFiltersRequest()); dispatch(refreshFiltersRequest());
dispatch(showLoading()); dispatch(showLoading());
try { try {
@ -122,7 +122,7 @@ export const refreshFilters = config => async (dispatch) => {
dispatch(refreshFiltersSuccess()); dispatch(refreshFiltersSuccess());
if (updated > 0) { if (updated > 0) {
dispatch(addSuccessToast(t('list_updated', { count: updated }))); dispatch(addSuccessToast(i18next.t('list_updated', { count: updated })));
} else { } else {
dispatch(addSuccessToast('all_lists_up_to_date_toast')); dispatch(addSuccessToast('all_lists_up_to_date_toast'));
} }
@ -140,7 +140,7 @@ export const setFiltersConfigRequest = createAction('SET_FILTERS_CONFIG_REQUEST'
export const setFiltersConfigFailure = createAction('SET_FILTERS_CONFIG_FAILURE'); export const setFiltersConfigFailure = createAction('SET_FILTERS_CONFIG_FAILURE');
export const setFiltersConfigSuccess = createAction('SET_FILTERS_CONFIG_SUCCESS'); export const setFiltersConfigSuccess = createAction('SET_FILTERS_CONFIG_SUCCESS');
export const setFiltersConfig = config => async (dispatch, getState) => { export const setFiltersConfig = (config) => async (dispatch, getState) => {
dispatch(setFiltersConfigRequest()); dispatch(setFiltersConfigRequest());
try { try {
const { enabled } = config; const { enabled } = config;
@ -170,7 +170,7 @@ export const checkHostSuccess = createAction('CHECK_HOST_SUCCESS');
* @param {string} host.name * @param {string} host.name
* @returns {undefined} * @returns {undefined}
*/ */
export const checkHost = host => async (dispatch) => { export const checkHost = (host) => async (dispatch) => {
dispatch(checkHostRequest()); dispatch(checkHostRequest());
try { try {
const data = await apiClient.checkHost(host); const data = await apiClient.checkHost(host);

View File

@ -1,16 +1,12 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import { t } from 'i18next'; import i18next from 'i18next';
import axios from 'axios'; import axios from 'axios';
import { normalizeTextarea, sortClients, isVersionGreater } from '../helpers/helpers'; import { isVersionGreater, normalizeTextarea, sortClients } from '../helpers/helpers';
import { SETTINGS_NAMES, CHECK_TIMEOUT } from '../helpers/constants'; import { CHECK_TIMEOUT, SETTINGS_NAMES } from '../helpers/constants';
import { getTlsStatus } from './encryption'; import { getTlsStatus } from './encryption';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addNoticeToast, addSuccessToast } from './toasts';
export const addErrorToast = createAction('ADD_ERROR_TOAST');
export const addSuccessToast = createAction('ADD_SUCCESS_TOAST');
export const addNoticeToast = createAction('ADD_NOTICE_TOAST');
export const removeToast = createAction('REMOVE_TOAST');
export const toggleSettingStatus = createAction('SETTING_STATUS_TOGGLE'); export const toggleSettingStatus = createAction('SETTING_STATUS_TOGGLE');
export const showSettingsFailure = createAction('SETTINGS_FAILURE_SHOW'); export const showSettingsFailure = createAction('SETTINGS_FAILURE_SHOW');
@ -62,7 +58,7 @@ export const initSettingsRequest = createAction('SETTINGS_INIT_REQUEST');
export const initSettingsFailure = createAction('SETTINGS_INIT_FAILURE'); export const initSettingsFailure = createAction('SETTINGS_INIT_FAILURE');
export const initSettingsSuccess = createAction('SETTINGS_INIT_SUCCESS'); export const initSettingsSuccess = createAction('SETTINGS_INIT_SUCCESS');
export const initSettings = settingsList => async (dispatch) => { export const initSettings = (settingsList) => async (dispatch) => {
dispatch(initSettingsRequest()); dispatch(initSettingsRequest());
try { try {
const safebrowsingStatus = await apiClient.getSafebrowsingStatus(); const safebrowsingStatus = await apiClient.getSafebrowsingStatus();
@ -89,7 +85,7 @@ export const toggleProtectionRequest = createAction('TOGGLE_PROTECTION_REQUEST')
export const toggleProtectionFailure = createAction('TOGGLE_PROTECTION_FAILURE'); export const toggleProtectionFailure = createAction('TOGGLE_PROTECTION_FAILURE');
export const toggleProtectionSuccess = createAction('TOGGLE_PROTECTION_SUCCESS'); export const toggleProtectionSuccess = createAction('TOGGLE_PROTECTION_SUCCESS');
export const toggleProtection = status => async (dispatch) => { export const toggleProtection = (status) => async (dispatch) => {
dispatch(toggleProtectionRequest()); dispatch(toggleProtectionRequest());
try { try {
const successMessage = status ? 'disabled_protection' : 'enabled_protection'; const successMessage = status ? 'disabled_protection' : 'enabled_protection';
@ -139,7 +135,7 @@ const checkStatus = async (handleRequestSuccess, handleRequestError, attempts =
handleRequestError(); handleRequestError();
} }
const rmTimeout = t => t && clearTimeout(t); const rmTimeout = (t) => t && clearTimeout(t);
try { try {
const response = await axios.get('control/status'); const response = await axios.get('control/status');
@ -270,7 +266,7 @@ export const testUpstreamRequest = createAction('TEST_UPSTREAM_REQUEST');
export const testUpstreamFailure = createAction('TEST_UPSTREAM_FAILURE'); export const testUpstreamFailure = createAction('TEST_UPSTREAM_FAILURE');
export const testUpstreamSuccess = createAction('TEST_UPSTREAM_SUCCESS'); export const testUpstreamSuccess = createAction('TEST_UPSTREAM_SUCCESS');
export const testUpstream = config => async (dispatch) => { export const testUpstream = (config) => async (dispatch) => {
dispatch(testUpstreamRequest()); dispatch(testUpstreamRequest());
try { try {
const values = { ...config }; const values = { ...config };
@ -281,12 +277,12 @@ export const testUpstream = config => async (dispatch) => {
const testMessages = Object.keys(upstreamResponse).map((key) => { const testMessages = Object.keys(upstreamResponse).map((key) => {
const message = upstreamResponse[key]; const message = upstreamResponse[key];
if (message !== 'OK') { if (message !== 'OK') {
dispatch(addErrorToast({ error: t('dns_test_not_ok_toast', { key }) })); dispatch(addErrorToast({ error: i18next.t('dns_test_not_ok_toast', { key }) }));
} }
return message; return message;
}); });
if (testMessages.every(message => message === 'OK')) { if (testMessages.every((message) => message === 'OK')) {
dispatch(addSuccessToast('dns_test_ok_toast')); dispatch(addSuccessToast('dns_test_ok_toast'));
} }
@ -301,7 +297,7 @@ export const changeLanguageRequest = createAction('CHANGE_LANGUAGE_REQUEST');
export const changeLanguageFailure = createAction('CHANGE_LANGUAGE_FAILURE'); export const changeLanguageFailure = createAction('CHANGE_LANGUAGE_FAILURE');
export const changeLanguageSuccess = createAction('CHANGE_LANGUAGE_SUCCESS'); export const changeLanguageSuccess = createAction('CHANGE_LANGUAGE_SUCCESS');
export const changeLanguage = lang => async (dispatch) => { export const changeLanguage = (lang) => async (dispatch) => {
dispatch(changeLanguageRequest()); dispatch(changeLanguageRequest());
try { try {
await apiClient.changeLanguage(lang); await apiClient.changeLanguage(lang);
@ -361,7 +357,7 @@ export const findActiveDhcpRequest = createAction('FIND_ACTIVE_DHCP_REQUEST');
export const findActiveDhcpSuccess = createAction('FIND_ACTIVE_DHCP_SUCCESS'); export const findActiveDhcpSuccess = createAction('FIND_ACTIVE_DHCP_SUCCESS');
export const findActiveDhcpFailure = createAction('FIND_ACTIVE_DHCP_FAILURE'); export const findActiveDhcpFailure = createAction('FIND_ACTIVE_DHCP_FAILURE');
export const findActiveDhcp = name => async (dispatch) => { export const findActiveDhcp = (name) => async (dispatch) => {
dispatch(findActiveDhcpRequest()); dispatch(findActiveDhcpRequest());
try { try {
const activeDhcp = await apiClient.findActiveDhcp(name); const activeDhcp = await apiClient.findActiveDhcp(name);
@ -376,7 +372,7 @@ export const setDhcpConfigRequest = createAction('SET_DHCP_CONFIG_REQUEST');
export const setDhcpConfigSuccess = createAction('SET_DHCP_CONFIG_SUCCESS'); export const setDhcpConfigSuccess = createAction('SET_DHCP_CONFIG_SUCCESS');
export const setDhcpConfigFailure = createAction('SET_DHCP_CONFIG_FAILURE'); export const setDhcpConfigFailure = createAction('SET_DHCP_CONFIG_FAILURE');
export const setDhcpConfig = values => async (dispatch, getState) => { export const setDhcpConfig = (values) => async (dispatch, getState) => {
const { config } = getState().dhcp; const { config } = getState().dhcp;
const updatedConfig = { ...config, ...values }; const updatedConfig = { ...config, ...values };
dispatch(setDhcpConfigRequest()); dispatch(setDhcpConfigRequest());
@ -395,7 +391,7 @@ export const toggleDhcpRequest = createAction('TOGGLE_DHCP_REQUEST');
export const toggleDhcpFailure = createAction('TOGGLE_DHCP_FAILURE'); export const toggleDhcpFailure = createAction('TOGGLE_DHCP_FAILURE');
export const toggleDhcpSuccess = createAction('TOGGLE_DHCP_SUCCESS'); export const toggleDhcpSuccess = createAction('TOGGLE_DHCP_SUCCESS');
export const toggleDhcp = values => async (dispatch) => { export const toggleDhcp = (values) => async (dispatch) => {
dispatch(toggleDhcpRequest()); dispatch(toggleDhcpRequest());
let config = { ...values, enabled: false }; let config = { ...values, enabled: false };
let successMessage = 'disabled_dhcp'; let successMessage = 'disabled_dhcp';
@ -438,13 +434,13 @@ export const addStaticLeaseRequest = createAction('ADD_STATIC_LEASE_REQUEST');
export const addStaticLeaseFailure = createAction('ADD_STATIC_LEASE_FAILURE'); export const addStaticLeaseFailure = createAction('ADD_STATIC_LEASE_FAILURE');
export const addStaticLeaseSuccess = createAction('ADD_STATIC_LEASE_SUCCESS'); export const addStaticLeaseSuccess = createAction('ADD_STATIC_LEASE_SUCCESS');
export const addStaticLease = config => async (dispatch) => { export const addStaticLease = (config) => async (dispatch) => {
dispatch(addStaticLeaseRequest()); dispatch(addStaticLeaseRequest());
try { try {
const name = config.hostname || config.ip; const name = config.hostname || config.ip;
await apiClient.addStaticLease(config); await apiClient.addStaticLease(config);
dispatch(addStaticLeaseSuccess(config)); dispatch(addStaticLeaseSuccess(config));
dispatch(addSuccessToast(t('dhcp_lease_added', { key: name }))); dispatch(addSuccessToast(i18next.t('dhcp_lease_added', { key: name })));
dispatch(toggleLeaseModal()); dispatch(toggleLeaseModal());
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));
@ -456,15 +452,17 @@ export const removeStaticLeaseRequest = createAction('REMOVE_STATIC_LEASE_REQUES
export const removeStaticLeaseFailure = createAction('REMOVE_STATIC_LEASE_FAILURE'); export const removeStaticLeaseFailure = createAction('REMOVE_STATIC_LEASE_FAILURE');
export const removeStaticLeaseSuccess = createAction('REMOVE_STATIC_LEASE_SUCCESS'); export const removeStaticLeaseSuccess = createAction('REMOVE_STATIC_LEASE_SUCCESS');
export const removeStaticLease = config => async (dispatch) => { export const removeStaticLease = (config) => async (dispatch) => {
dispatch(removeStaticLeaseRequest()); dispatch(removeStaticLeaseRequest());
try { try {
const name = config.hostname || config.ip; const name = config.hostname || config.ip;
await apiClient.removeStaticLease(config); await apiClient.removeStaticLease(config);
dispatch(removeStaticLeaseSuccess(config)); dispatch(removeStaticLeaseSuccess(config));
dispatch(addSuccessToast(t('dhcp_lease_deleted', { key: name }))); dispatch(addSuccessToast(i18next.t('dhcp_lease_deleted', { key: name })));
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));
dispatch(removeStaticLeaseFailure()); dispatch(removeStaticLeaseFailure());
} }
}; };
export const removeToast = createAction('REMOVE_TOAST');

View File

@ -1,6 +1,6 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index'; import { addErrorToast, addSuccessToast } from './toasts';
export const nextStep = createAction('NEXT_STEP'); export const nextStep = createAction('NEXT_STEP');
export const prevStep = createAction('PREV_STEP'); export const prevStep = createAction('PREV_STEP');
@ -24,7 +24,7 @@ export const setAllSettingsRequest = createAction('SET_ALL_SETTINGS_REQUEST');
export const setAllSettingsFailure = createAction('SET_ALL_SETTINGS_FAILURE'); export const setAllSettingsFailure = createAction('SET_ALL_SETTINGS_FAILURE');
export const setAllSettingsSuccess = createAction('SET_ALL_SETTINGS_SUCCESS'); export const setAllSettingsSuccess = createAction('SET_ALL_SETTINGS_SUCCESS');
export const setAllSettings = values => async (dispatch) => { export const setAllSettings = (values) => async (dispatch) => {
dispatch(setAllSettingsRequest()); dispatch(setAllSettingsRequest());
try { try {
const { const {
@ -47,7 +47,7 @@ export const checkConfigRequest = createAction('CHECK_CONFIG_REQUEST');
export const checkConfigFailure = createAction('CHECK_CONFIG_FAILURE'); export const checkConfigFailure = createAction('CHECK_CONFIG_FAILURE');
export const checkConfigSuccess = createAction('CHECK_CONFIG_SUCCESS'); export const checkConfigSuccess = createAction('CHECK_CONFIG_SUCCESS');
export const checkConfig = values => async (dispatch) => { export const checkConfig = (values) => async (dispatch) => {
dispatch(checkConfigRequest()); dispatch(checkConfigRequest());
try { try {
const check = await apiClient.checkConfig(values); const check = await apiClient.checkConfig(values);

View File

@ -1,13 +1,13 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import { addErrorToast } from './index';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast } from './toasts';
export const processLoginRequest = createAction('PROCESS_LOGIN_REQUEST'); export const processLoginRequest = createAction('PROCESS_LOGIN_REQUEST');
export const processLoginFailure = createAction('PROCESS_LOGIN_FAILURE'); export const processLoginFailure = createAction('PROCESS_LOGIN_FAILURE');
export const processLoginSuccess = createAction('PROCESS_LOGIN_SUCCESS'); export const processLoginSuccess = createAction('PROCESS_LOGIN_SUCCESS');
export const processLogin = values => async (dispatch) => { export const processLogin = (values) => async (dispatch) => {
dispatch(processLoginRequest()); dispatch(processLoginRequest());
try { try {
await apiClient.login(values); await apiClient.login(values);

View File

@ -1,9 +1,9 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index';
import { normalizeLogs, getParamsForClientsSearch, addClientInfo } from '../helpers/helpers'; import { normalizeLogs, getParamsForClientsSearch, addClientInfo } from '../helpers/helpers';
import { TABLE_DEFAULT_PAGE_SIZE } from '../helpers/constants'; import { TABLE_DEFAULT_PAGE_SIZE } from '../helpers/constants';
import { addErrorToast, addSuccessToast } from './toasts';
const getLogsWithParams = async (config) => { const getLogsWithParams = async (config) => {
const { older_than, filter, ...values } = config; const { older_than, filter, ...values } = config;
@ -27,9 +27,9 @@ const checkFilteredLogs = async (data, filter, dispatch, total) => {
const { logs, oldest } = data; const { logs, oldest } = data;
const totalData = total || { logs }; const totalData = total || { logs };
const needToGetAdditionalLogs = (logs.length < TABLE_DEFAULT_PAGE_SIZE || const needToGetAdditionalLogs = (logs.length < TABLE_DEFAULT_PAGE_SIZE
totalData.logs.length < TABLE_DEFAULT_PAGE_SIZE) && || totalData.logs.length < TABLE_DEFAULT_PAGE_SIZE)
oldest !== ''; && oldest !== '';
if (needToGetAdditionalLogs) { if (needToGetAdditionalLogs) {
dispatch(getAdditionalLogsRequest()); dispatch(getAdditionalLogsRequest());
@ -61,7 +61,7 @@ export const getLogsRequest = createAction('GET_LOGS_REQUEST');
export const getLogsFailure = createAction('GET_LOGS_FAILURE'); export const getLogsFailure = createAction('GET_LOGS_FAILURE');
export const getLogsSuccess = createAction('GET_LOGS_SUCCESS'); export const getLogsSuccess = createAction('GET_LOGS_SUCCESS');
export const getLogs = config => async (dispatch, getState) => { export const getLogs = (config) => async (dispatch, getState) => {
dispatch(getLogsRequest()); dispatch(getLogsRequest());
try { try {
const { isFiltered, filter, page } = getState().queryLogs; const { isFiltered, filter, page } = getState().queryLogs;
@ -85,7 +85,7 @@ export const setLogsFilterRequest = createAction('SET_LOGS_FILTER_REQUEST');
export const setLogsFilterFailure = createAction('SET_LOGS_FILTER_FAILURE'); export const setLogsFilterFailure = createAction('SET_LOGS_FILTER_FAILURE');
export const setLogsFilterSuccess = createAction('SET_LOGS_FILTER_SUCCESS'); export const setLogsFilterSuccess = createAction('SET_LOGS_FILTER_SUCCESS');
export const setLogsFilter = filter => async (dispatch) => { export const setLogsFilter = (filter) => async (dispatch) => {
dispatch(setLogsFilterRequest()); dispatch(setLogsFilterRequest());
try { try {
const data = await getLogsWithParams({ older_than: '', filter }); const data = await getLogsWithParams({ older_than: '', filter });
@ -135,7 +135,7 @@ export const setLogsConfigRequest = createAction('SET_LOGS_CONFIG_REQUEST');
export const setLogsConfigFailure = createAction('SET_LOGS_CONFIG_FAILURE'); export const setLogsConfigFailure = createAction('SET_LOGS_CONFIG_FAILURE');
export const setLogsConfigSuccess = createAction('SET_LOGS_CONFIG_SUCCESS'); export const setLogsConfigSuccess = createAction('SET_LOGS_CONFIG_SUCCESS');
export const setLogsConfig = config => async (dispatch) => { export const setLogsConfig = (config) => async (dispatch) => {
dispatch(setLogsConfigRequest()); dispatch(setLogsConfigRequest());
try { try {
await apiClient.setQueryLogConfig(config); await apiClient.setQueryLogConfig(config);

View File

@ -1,7 +1,7 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import { t } from 'i18next'; import i18next from 'i18next';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index'; import { addErrorToast, addSuccessToast } from './toasts';
export const toggleRewritesModal = createAction('TOGGLE_REWRITES_MODAL'); export const toggleRewritesModal = createAction('TOGGLE_REWRITES_MODAL');
@ -24,14 +24,14 @@ export const addRewriteRequest = createAction('ADD_REWRITE_REQUEST');
export const addRewriteFailure = createAction('ADD_REWRITE_FAILURE'); export const addRewriteFailure = createAction('ADD_REWRITE_FAILURE');
export const addRewriteSuccess = createAction('ADD_REWRITE_SUCCESS'); export const addRewriteSuccess = createAction('ADD_REWRITE_SUCCESS');
export const addRewrite = config => async (dispatch) => { export const addRewrite = (config) => async (dispatch) => {
dispatch(addRewriteRequest()); dispatch(addRewriteRequest());
try { try {
await apiClient.addRewrite(config); await apiClient.addRewrite(config);
dispatch(addRewriteSuccess(config)); dispatch(addRewriteSuccess(config));
dispatch(toggleRewritesModal()); dispatch(toggleRewritesModal());
dispatch(getRewritesList()); dispatch(getRewritesList());
dispatch(addSuccessToast(t('rewrite_added', { key: config.domain }))); dispatch(addSuccessToast(i18next.t('rewrite_added', { key: config.domain })));
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));
dispatch(addRewriteFailure()); dispatch(addRewriteFailure());
@ -42,13 +42,13 @@ export const deleteRewriteRequest = createAction('DELETE_REWRITE_REQUEST');
export const deleteRewriteFailure = createAction('DELETE_REWRITE_FAILURE'); export const deleteRewriteFailure = createAction('DELETE_REWRITE_FAILURE');
export const deleteRewriteSuccess = createAction('DELETE_REWRITE_SUCCESS'); export const deleteRewriteSuccess = createAction('DELETE_REWRITE_SUCCESS');
export const deleteRewrite = config => async (dispatch) => { export const deleteRewrite = (config) => async (dispatch) => {
dispatch(deleteRewriteRequest()); dispatch(deleteRewriteRequest());
try { try {
await apiClient.deleteRewrite(config); await apiClient.deleteRewrite(config);
dispatch(deleteRewriteSuccess()); dispatch(deleteRewriteSuccess());
dispatch(getRewritesList()); dispatch(getRewritesList());
dispatch(addSuccessToast(t('rewrite_deleted', { key: config.domain }))); dispatch(addSuccessToast(i18next.t('rewrite_deleted', { key: config.domain })));
} catch (error) { } catch (error) {
dispatch(addErrorToast({ error })); dispatch(addErrorToast({ error }));
dispatch(deleteRewriteFailure()); dispatch(deleteRewriteFailure());

View File

@ -1,6 +1,6 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index'; import { addErrorToast, addSuccessToast } from './toasts';
export const getBlockedServicesRequest = createAction('GET_BLOCKED_SERVICES_REQUEST'); export const getBlockedServicesRequest = createAction('GET_BLOCKED_SERVICES_REQUEST');
export const getBlockedServicesFailure = createAction('GET_BLOCKED_SERVICES_FAILURE'); export const getBlockedServicesFailure = createAction('GET_BLOCKED_SERVICES_FAILURE');
@ -21,7 +21,7 @@ export const setBlockedServicesRequest = createAction('SET_BLOCKED_SERVICES_REQU
export const setBlockedServicesFailure = createAction('SET_BLOCKED_SERVICES_FAILURE'); export const setBlockedServicesFailure = createAction('SET_BLOCKED_SERVICES_FAILURE');
export const setBlockedServicesSuccess = createAction('SET_BLOCKED_SERVICES_SUCCESS'); export const setBlockedServicesSuccess = createAction('SET_BLOCKED_SERVICES_SUCCESS');
export const setBlockedServices = values => async (dispatch) => { export const setBlockedServices = (values) => async (dispatch) => {
dispatch(setBlockedServicesRequest()); dispatch(setBlockedServicesRequest());
try { try {
await apiClient.setBlockedServices(values); await apiClient.setBlockedServices(values);

View File

@ -1,8 +1,10 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index'; import {
import { normalizeTopStats, secondsToMilliseconds, getParamsForClientsSearch, addClientInfo } from '../helpers/helpers'; normalizeTopStats, secondsToMilliseconds, getParamsForClientsSearch, addClientInfo,
} from '../helpers/helpers';
import { addErrorToast, addSuccessToast } from './toasts';
export const getStatsConfigRequest = createAction('GET_STATS_CONFIG_REQUEST'); export const getStatsConfigRequest = createAction('GET_STATS_CONFIG_REQUEST');
export const getStatsConfigFailure = createAction('GET_STATS_CONFIG_FAILURE'); export const getStatsConfigFailure = createAction('GET_STATS_CONFIG_FAILURE');
@ -23,7 +25,7 @@ export const setStatsConfigRequest = createAction('SET_STATS_CONFIG_REQUEST');
export const setStatsConfigFailure = createAction('SET_STATS_CONFIG_FAILURE'); export const setStatsConfigFailure = createAction('SET_STATS_CONFIG_FAILURE');
export const setStatsConfigSuccess = createAction('SET_STATS_CONFIG_SUCCESS'); export const setStatsConfigSuccess = createAction('SET_STATS_CONFIG_SUCCESS');
export const setStatsConfig = config => async (dispatch) => { export const setStatsConfig = (config) => async (dispatch) => {
dispatch(setStatsConfigRequest()); dispatch(setStatsConfigRequest());
try { try {
await apiClient.setStatsConfig(config); await apiClient.setStatsConfig(config);

View File

@ -0,0 +1,5 @@
import { createAction } from 'redux-actions';
export const addErrorToast = createAction('ADD_ERROR_TOAST');
export const addSuccessToast = createAction('ADD_SUCCESS_TOAST');
export const addNoticeToast = createAction('ADD_NOTICE_TOAST');

View File

@ -32,8 +32,11 @@ class Api {
// Global methods // Global methods
GLOBAL_STATUS = { path: 'status', method: 'GET' }; GLOBAL_STATUS = { path: 'status', method: 'GET' };
GLOBAL_TEST_UPSTREAM_DNS = { path: 'test_upstream_dns', method: 'POST' }; GLOBAL_TEST_UPSTREAM_DNS = { path: 'test_upstream_dns', method: 'POST' };
GLOBAL_VERSION = { path: 'version.json', method: 'POST' }; GLOBAL_VERSION = { path: 'version.json', method: 'POST' };
GLOBAL_UPDATE = { path: 'update', method: 'POST' }; GLOBAL_UPDATE = { path: 'update', method: 'POST' };
getGlobalStatus() { getGlobalStatus() {
@ -66,12 +69,19 @@ class Api {
// Filtering // Filtering
FILTERING_STATUS = { path: 'filtering/status', method: 'GET' }; FILTERING_STATUS = { path: 'filtering/status', method: 'GET' };
FILTERING_ADD_FILTER = { path: 'filtering/add_url', method: 'POST' }; FILTERING_ADD_FILTER = { path: 'filtering/add_url', method: 'POST' };
FILTERING_REMOVE_FILTER = { path: 'filtering/remove_url', method: 'POST' }; FILTERING_REMOVE_FILTER = { path: 'filtering/remove_url', method: 'POST' };
FILTERING_SET_RULES = { path: 'filtering/set_rules', method: 'POST' }; FILTERING_SET_RULES = { path: 'filtering/set_rules', method: 'POST' };
FILTERING_REFRESH = { path: 'filtering/refresh', method: 'POST' }; FILTERING_REFRESH = { path: 'filtering/refresh', method: 'POST' };
FILTERING_SET_URL = { path: 'filtering/set_url', method: 'POST' }; FILTERING_SET_URL = { path: 'filtering/set_url', method: 'POST' };
FILTERING_CONFIG = { path: 'filtering/config', method: 'POST' }; FILTERING_CONFIG = { path: 'filtering/config', method: 'POST' };
FILTERING_CHECK_HOST = { path: 'filtering/check_host', method: 'GET' }; FILTERING_CHECK_HOST = { path: 'filtering/check_host', method: 'GET' };
getFilteringStatus() { getFilteringStatus() {
@ -144,7 +154,9 @@ class Api {
// Parental // Parental
PARENTAL_STATUS = { path: 'parental/status', method: 'GET' }; PARENTAL_STATUS = { path: 'parental/status', method: 'GET' };
PARENTAL_ENABLE = { path: 'parental/enable', method: 'POST' }; PARENTAL_ENABLE = { path: 'parental/enable', method: 'POST' };
PARENTAL_DISABLE = { path: 'parental/disable', method: 'POST' }; PARENTAL_DISABLE = { path: 'parental/disable', method: 'POST' };
getParentalStatus() { getParentalStatus() {
@ -169,7 +181,9 @@ class Api {
// Safebrowsing // Safebrowsing
SAFEBROWSING_STATUS = { path: 'safebrowsing/status', method: 'GET' }; SAFEBROWSING_STATUS = { path: 'safebrowsing/status', method: 'GET' };
SAFEBROWSING_ENABLE = { path: 'safebrowsing/enable', method: 'POST' }; SAFEBROWSING_ENABLE = { path: 'safebrowsing/enable', method: 'POST' };
SAFEBROWSING_DISABLE = { path: 'safebrowsing/disable', method: 'POST' }; SAFEBROWSING_DISABLE = { path: 'safebrowsing/disable', method: 'POST' };
getSafebrowsingStatus() { getSafebrowsingStatus() {
@ -189,7 +203,9 @@ class Api {
// Safesearch // Safesearch
SAFESEARCH_STATUS = { path: 'safesearch/status', method: 'GET' }; SAFESEARCH_STATUS = { path: 'safesearch/status', method: 'GET' };
SAFESEARCH_ENABLE = { path: 'safesearch/enable', method: 'POST' }; SAFESEARCH_ENABLE = { path: 'safesearch/enable', method: 'POST' };
SAFESEARCH_DISABLE = { path: 'safesearch/disable', method: 'POST' }; SAFESEARCH_DISABLE = { path: 'safesearch/disable', method: 'POST' };
getSafesearchStatus() { getSafesearchStatus() {
@ -209,6 +225,7 @@ class Api {
// Language // Language
CURRENT_LANGUAGE = { path: 'i18n/current_language', method: 'GET' }; CURRENT_LANGUAGE = { path: 'i18n/current_language', method: 'GET' };
CHANGE_LANGUAGE = { path: 'i18n/change_language', method: 'POST' }; CHANGE_LANGUAGE = { path: 'i18n/change_language', method: 'POST' };
getCurrentLanguage() { getCurrentLanguage() {
@ -227,11 +244,17 @@ class Api {
// DHCP // DHCP
DHCP_STATUS = { path: 'dhcp/status', method: 'GET' }; DHCP_STATUS = { path: 'dhcp/status', method: 'GET' };
DHCP_SET_CONFIG = { path: 'dhcp/set_config', method: 'POST' }; DHCP_SET_CONFIG = { path: 'dhcp/set_config', method: 'POST' };
DHCP_FIND_ACTIVE = { path: 'dhcp/find_active_dhcp', method: 'POST' }; DHCP_FIND_ACTIVE = { path: 'dhcp/find_active_dhcp', method: 'POST' };
DHCP_INTERFACES = { path: 'dhcp/interfaces', method: 'GET' }; DHCP_INTERFACES = { path: 'dhcp/interfaces', method: 'GET' };
DHCP_ADD_STATIC_LEASE = { path: 'dhcp/add_static_lease', method: 'POST' }; DHCP_ADD_STATIC_LEASE = { path: 'dhcp/add_static_lease', method: 'POST' };
DHCP_REMOVE_STATIC_LEASE = { path: 'dhcp/remove_static_lease', method: 'POST' }; DHCP_REMOVE_STATIC_LEASE = { path: 'dhcp/remove_static_lease', method: 'POST' };
DHCP_RESET = { path: 'dhcp/reset', method: 'POST' }; DHCP_RESET = { path: 'dhcp/reset', method: 'POST' };
getDhcpStatus() { getDhcpStatus() {
@ -287,7 +310,9 @@ class Api {
// Installation // Installation
INSTALL_GET_ADDRESSES = { path: 'install/get_addresses', method: 'GET' }; INSTALL_GET_ADDRESSES = { path: 'install/get_addresses', method: 'GET' };
INSTALL_CONFIGURE = { path: 'install/configure', method: 'POST' }; INSTALL_CONFIGURE = { path: 'install/configure', method: 'POST' };
INSTALL_CHECK_CONFIG = { path: 'install/check_config', method: 'POST' }; INSTALL_CHECK_CONFIG = { path: 'install/check_config', method: 'POST' };
getDefaultAddresses() { getDefaultAddresses() {
@ -315,7 +340,9 @@ class Api {
// DNS-over-HTTPS and DNS-over-TLS // DNS-over-HTTPS and DNS-over-TLS
TLS_STATUS = { path: 'tls/status', method: 'GET' }; TLS_STATUS = { path: 'tls/status', method: 'GET' };
TLS_CONFIG = { path: 'tls/configure', method: 'POST' }; TLS_CONFIG = { path: 'tls/configure', method: 'POST' };
TLS_VALIDATE = { path: 'tls/validate', method: 'POST' }; TLS_VALIDATE = { path: 'tls/validate', method: 'POST' };
getTlsStatus() { getTlsStatus() {
@ -343,9 +370,13 @@ class Api {
// Per-client settings // Per-client settings
GET_CLIENTS = { path: 'clients', method: 'GET' }; GET_CLIENTS = { path: 'clients', method: 'GET' };
FIND_CLIENTS = { path: 'clients/find', method: 'GET' }; FIND_CLIENTS = { path: 'clients/find', method: 'GET' };
ADD_CLIENT = { path: 'clients/add', method: 'POST' }; ADD_CLIENT = { path: 'clients/add', method: 'POST' };
DELETE_CLIENT = { path: 'clients/delete', method: 'POST' }; DELETE_CLIENT = { path: 'clients/delete', method: 'POST' };
UPDATE_CLIENT = { path: 'clients/update', method: 'POST' }; UPDATE_CLIENT = { path: 'clients/update', method: 'POST' };
getClients() { getClients() {
@ -388,6 +419,7 @@ class Api {
// DNS access settings // DNS access settings
ACCESS_LIST = { path: 'access/list', method: 'GET' }; ACCESS_LIST = { path: 'access/list', method: 'GET' };
ACCESS_SET = { path: 'access/set', method: 'POST' }; ACCESS_SET = { path: 'access/set', method: 'POST' };
getAccessList() { getAccessList() {
@ -406,7 +438,9 @@ class Api {
// DNS rewrites // DNS rewrites
REWRITES_LIST = { path: 'rewrite/list', method: 'GET' }; REWRITES_LIST = { path: 'rewrite/list', method: 'GET' };
REWRITE_ADD = { path: 'rewrite/add', method: 'POST' }; REWRITE_ADD = { path: 'rewrite/add', method: 'POST' };
REWRITE_DELETE = { path: 'rewrite/delete', method: 'POST' }; REWRITE_DELETE = { path: 'rewrite/delete', method: 'POST' };
getRewritesList() { getRewritesList() {
@ -434,6 +468,7 @@ class Api {
// Blocked services // Blocked services
BLOCKED_SERVICES_LIST = { path: 'blocked_services/list', method: 'GET' }; BLOCKED_SERVICES_LIST = { path: 'blocked_services/list', method: 'GET' };
BLOCKED_SERVICES_SET = { path: 'blocked_services/set', method: 'POST' }; BLOCKED_SERVICES_SET = { path: 'blocked_services/set', method: 'POST' };
getBlockedServices() { getBlockedServices() {
@ -452,8 +487,11 @@ class Api {
// Settings for statistics // Settings for statistics
GET_STATS = { path: 'stats', method: 'GET' }; GET_STATS = { path: 'stats', method: 'GET' };
STATS_INFO = { path: 'stats_info', method: 'GET' }; STATS_INFO = { path: 'stats_info', method: 'GET' };
STATS_CONFIG = { path: 'stats_config', method: 'POST' }; STATS_CONFIG = { path: 'stats_config', method: 'POST' };
STATS_RESET = { path: 'stats_reset', method: 'POST' }; STATS_RESET = { path: 'stats_reset', method: 'POST' };
getStats() { getStats() {
@ -482,8 +520,11 @@ class Api {
// Query log // Query log
GET_QUERY_LOG = { path: 'querylog', method: 'GET' }; GET_QUERY_LOG = { path: 'querylog', method: 'GET' };
QUERY_LOG_CONFIG = { path: 'querylog_config', method: 'POST' }; QUERY_LOG_CONFIG = { path: 'querylog_config', method: 'POST' };
QUERY_LOG_INFO = { path: 'querylog_info', method: 'GET' }; QUERY_LOG_INFO = { path: 'querylog_info', method: 'GET' };
QUERY_LOG_CLEAR = { path: 'querylog_clear', method: 'POST' }; QUERY_LOG_CLEAR = { path: 'querylog_clear', method: 'POST' };
getQueryLog(params) { getQueryLog(params) {
@ -533,6 +574,7 @@ class Api {
// DNS config // DNS config
GET_DNS_CONFIG = { path: 'dns_info', method: 'GET' }; GET_DNS_CONFIG = { path: 'dns_info', method: 'GET' };
SET_DNS_CONFIG = { path: 'dns_config', method: 'POST' }; SET_DNS_CONFIG = { path: 'dns_config', method: 'POST' };
getDnsConfig() { getDnsConfig() {

View File

@ -1,5 +1,5 @@
:root { :root {
font-family-monospace: Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro, monospace; --font-family-monospace: Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro, monospace;
} }
body { body {

View File

@ -1,7 +1,7 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { HashRouter, Route } from 'react-router-dom'; import { HashRouter, Route } from 'react-router-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import LoadingBar from 'react-redux-loading-bar'; import LoadingBar from 'react-redux-loading-bar';
import 'react-table/react-table.css'; import 'react-table/react-table.css';
@ -147,4 +147,4 @@ App.propTypes = {
getVersion: PropTypes.func, getVersion: PropTypes.func,
}; };
export default withNamespaces()(App); export default withTranslation()(App);

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation, Trans } from 'react-i18next';
import Card from '../ui/Card'; import Card from '../ui/Card';
import Cell from '../ui/Cell'; import Cell from '../ui/Cell';
@ -10,13 +10,12 @@ import DomainCell from './DomainCell';
import { getPercent } from '../../helpers/helpers'; import { getPercent } from '../../helpers/helpers';
import { STATUS_COLORS } from '../../helpers/constants'; import { STATUS_COLORS } from '../../helpers/constants';
const CountCell = totalBlocked => const CountCell = (totalBlocked) => function cell(row) {
function cell(row) { const { value } = row;
const { value } = row; const percent = getPercent(totalBlocked, value);
const percent = getPercent(totalBlocked, value);
return <Cell value={value} percent={percent} color={STATUS_COLORS.red} />; return <Cell value={value} percent={percent} color={STATUS_COLORS.red} />;
}; };
const BlockedDomains = ({ const BlockedDomains = ({
t, t,
@ -74,4 +73,4 @@ BlockedDomains.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(BlockedDomains); export default withTranslation()(BlockedDomains);

View File

@ -1,7 +1,7 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import Card from '../ui/Card'; import Card from '../ui/Card';
import Cell from '../ui/Cell'; import Cell from '../ui/Cell';
@ -13,20 +13,19 @@ import { formatClientCell } from '../../helpers/formatClientCell';
const getClientsPercentColor = (percent) => { const getClientsPercentColor = (percent) => {
if (percent > 50) { if (percent > 50) {
return STATUS_COLORS.green; return STATUS_COLORS.green;
} else if (percent > 10) { } if (percent > 10) {
return STATUS_COLORS.yellow; return STATUS_COLORS.yellow;
} }
return STATUS_COLORS.red; return STATUS_COLORS.red;
}; };
const countCell = dnsQueries => const countCell = (dnsQueries) => function cell(row) {
function cell(row) { const { value } = row;
const { value } = row; const percent = getPercent(dnsQueries, value);
const percent = getPercent(dnsQueries, value); const percentColor = getClientsPercentColor(percent);
const percentColor = getClientsPercentColor(percent);
return <Cell value={value} percent={percent} color={percentColor} />; return <Cell value={value} percent={percent} color={percentColor} />;
}; };
const renderBlockingButton = (blocked, ip, handleClick, processing) => { const renderBlockingButton = (blocked, ip, handleClick, processing) => {
let buttonProps = { let buttonProps = {
@ -59,20 +58,19 @@ const renderBlockingButton = (blocked, ip, handleClick, processing) => {
const isBlockedClient = (clients, ip) => !!(clients && clients.includes(ip)); const isBlockedClient = (clients, ip) => !!(clients && clients.includes(ip));
const clientCell = (t, toggleClientStatus, processing, disallowedClients) => const clientCell = (t, toggleClientStatus, processing, disallowedClients) => function cell(row) {
function cell(row) { const { value } = row;
const { value } = row; const blocked = isBlockedClient(disallowedClients, value);
const blocked = isBlockedClient(disallowedClients, value);
return ( return (
<Fragment> <Fragment>
<div className="logs__row logs__row--overflow logs__row--column"> <div className="logs__row logs__row--overflow logs__row--column">
{formatClientCell(row, t)} {formatClientCell(row, t)}
</div> </div>
{renderBlockingButton(blocked, value, toggleClientStatus, processing)} {renderBlockingButton(blocked, value, toggleClientStatus, processing)}
</Fragment> </Fragment>
); );
}; };
const Clients = ({ const Clients = ({
t, t,
@ -103,8 +101,7 @@ const Clients = ({
{ {
Header: 'IP', Header: 'IP',
accessor: 'ip', accessor: 'ip',
sortMethod: (a, b) => sortMethod: (a, b) => parseInt(a.replace(/\./g, ''), 10) - parseInt(b.replace(/\./g, ''), 10),
parseInt(a.replace(/\./g, ''), 10) - parseInt(b.replace(/\./g, ''), 10),
Cell: clientCell(t, toggleClientStatus, processingAccessSet, disallowedClients), Cell: clientCell(t, toggleClientStatus, processingAccessSet, disallowedClients),
}, },
{ {
@ -154,4 +151,4 @@ Clients.propTypes = {
disallowedClients: PropTypes.string.isRequired, disallowedClients: PropTypes.string.isRequired,
}; };
export default withNamespaces()(Clients); export default withTranslation()(Clients);

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import round from 'lodash/round'; import round from 'lodash/round';
import Card from '../ui/Card'; import Card from '../ui/Card';
@ -23,10 +23,9 @@ const Counters = (props) => {
avgProcessingTime, avgProcessingTime,
} = props; } = props;
const tooltipTitle = const tooltipTitle = interval === 1
interval === 1 ? t('number_of_dns_query_24_hours')
? t('number_of_dns_query_24_hours') : t('number_of_dns_query_days', { count: interval });
: t('number_of_dns_query_days', { count: interval });
return ( return (
<Card <Card
@ -136,4 +135,4 @@ Counters.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Counters); export default withTranslation()(Counters);

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation, Trans } from 'react-i18next';
import Card from '../ui/Card'; import Card from '../ui/Card';
import Cell from '../ui/Cell'; import Cell from '../ui/Cell';
@ -13,20 +13,19 @@ import { getPercent } from '../../helpers/helpers';
const getQueriedPercentColor = (percent) => { const getQueriedPercentColor = (percent) => {
if (percent > 10) { if (percent > 10) {
return STATUS_COLORS.red; return STATUS_COLORS.red;
} else if (percent > 5) { } if (percent > 5) {
return STATUS_COLORS.yellow; return STATUS_COLORS.yellow;
} }
return STATUS_COLORS.green; return STATUS_COLORS.green;
}; };
const countCell = dnsQueries => const countCell = (dnsQueries) => function cell(row) {
function cell(row) { const { value } = row;
const { value } = row; const percent = getPercent(dnsQueries, value);
const percent = getPercent(dnsQueries, value); const percentColor = getQueriedPercentColor(percent);
const percentColor = getQueriedPercentColor(percent);
return <Cell value={value} percent={percent} color={percentColor} />; return <Cell value={value} percent={percent} color={percentColor} />;
}; };
const QueriedDomains = ({ const QueriedDomains = ({
t, refreshButton, topQueriedDomains, subtitle, dnsQueries, t, refreshButton, topQueriedDomains, subtitle, dnsQueries,
@ -72,4 +71,4 @@ QueriedDomains.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(QueriedDomains); export default withTranslation()(QueriedDomains);

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation, Trans } from 'react-i18next';
import StatsCard from './StatsCard'; import StatsCard from './StatsCard';
import { getPercent, normalizeHistory } from '../../helpers/helpers'; import { getPercent, normalizeHistory } from '../../helpers/helpers';
@ -76,4 +76,4 @@ Statistics.propTypes = {
refreshButton: PropTypes.node.isRequired, refreshButton: PropTypes.node.isRequired,
}; };
export default withNamespaces()(Statistics); export default withTranslation()(Statistics);

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import Statistics from './Statistics'; import Statistics from './Statistics';
import Counters from './Counters'; import Counters from './Counters';
@ -57,10 +57,9 @@ class Dashboard extends Component {
|| stats.processingGetConfig || stats.processingGetConfig
|| access.processing; || access.processing;
const subtitle = const subtitle = stats.interval === 1
stats.interval === 1 ? t('for_last_24_hours')
? t('for_last_24_hours') : t('for_last_days', { count: stats.interval });
: t('for_last_days', { count: stats.interval });
const refreshFullButton = ( const refreshFullButton = (
<button <button
@ -173,4 +172,4 @@ Dashboard.propTypes = {
getAccessList: PropTypes.func.isRequired, getAccessList: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Dashboard); export default withTranslation()(Dashboard);

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation, Trans } from 'react-i18next';
const Actions = ({ const Actions = ({
handleAdd, handleRefresh, processingRefreshFilters, whitelist, handleAdd, handleRefresh, processingRefreshFilters, whitelist,
@ -35,5 +35,4 @@ Actions.propTypes = {
whitelist: PropTypes.bool, whitelist: PropTypes.bool,
}; };
export default withNamespaces()(Actions); export default withTranslation()(Actions);

View File

@ -1,6 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import { import {
checkFiltered, checkFiltered,
@ -20,8 +20,8 @@ const getFilterName = (id, filters, whitelistFilters, t) => {
return t('filtered_custom_rules'); return t('filtered_custom_rules');
} }
const filter = filters.find(filter => filter.id === id) const filter = filters.find((filter) => filter.id === id)
|| whitelistFilters.find(filter => filter.id === id); || whitelistFilters.find((filter) => filter.id === id);
if (filter && filter.name) { if (filter && filter.name) {
return t('query_log_filtered', { filter: filter.name }); return t('query_log_filtered', { filter: filter.name });
@ -80,9 +80,9 @@ const getTitle = (reason, filterName, t, onlyFiltered) => {
const getColor = (reason) => { const getColor = (reason) => {
if (checkFiltered(reason)) { if (checkFiltered(reason)) {
return 'red'; return 'red';
} else if (checkRewrite(reason) || checkRewriteHosts(reason)) { } if (checkRewrite(reason) || checkRewriteHosts(reason)) {
return 'blue'; return 'blue';
} else if (checkWhiteList(reason)) { } if (checkWhiteList(reason)) {
return 'green'; return 'green';
} }
@ -162,4 +162,4 @@ Info.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Info); export default withTranslation()(Info);

View File

@ -1,6 +1,6 @@
import React, { Fragment } 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, withTranslation } from 'react-i18next';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import Card from '../../ui/Card'; import Card from '../../ui/Card';
@ -51,7 +51,7 @@ const Check = (props) => {
<button <button
className="btn btn-success btn-standard btn-large" className="btn btn-success btn-standard btn-large"
type="submit" type="submit"
onClick={this.handleSubmit} onClick={handleSubmit}
disabled={pristine || invalid || processing} disabled={pristine || invalid || processing}
> >
<Trans>check</Trans> <Trans>check</Trans>
@ -93,6 +93,6 @@ Check.propTypes = {
}; };
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ form: 'domainCheckForm' }), reduxForm({ form: 'domainCheckForm' }),
])(Check); ])(Check);

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import Card from '../ui/Card'; import Card from '../ui/Card';
import PageTitle from '../ui/PageTitle'; import PageTitle from '../ui/PageTitle';
@ -92,4 +92,4 @@ CustomRules.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(CustomRules); export default withTranslation()(CustomRules);

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import PageTitle from '../ui/PageTitle'; import PageTitle from '../ui/PageTitle';
import Card from '../ui/Card'; import Card from '../ui/Card';
@ -131,4 +131,4 @@ DnsAllowlist.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(DnsAllowlist); export default withTranslation()(DnsAllowlist);

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import PageTitle from '../ui/PageTitle'; import PageTitle from '../ui/PageTitle';
import Card from '../ui/Card'; import Card from '../ui/Card';
@ -122,4 +122,4 @@ DnsBlocklist.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(DnsBlocklist); export default withTranslation()(DnsBlocklist);

View File

@ -1,5 +1,5 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation, Trans } from 'react-i18next';
const Examples = () => ( const Examples = () => (
<Fragment> <Fragment>
@ -51,4 +51,4 @@ const Examples = () => (
</Fragment> </Fragment>
); );
export default withNamespaces()(Examples); export default withTranslation()(Examples);

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { renderInputField, required, isValidPath } from '../../helpers/form'; import { renderInputField, required, isValidPath } from '../../helpers/form';
@ -28,7 +28,7 @@ const Form = (props) => {
className="form-control" className="form-control"
placeholder={t('enter_name_hint')} placeholder={t('enter_name_hint')}
validate={[required]} validate={[required]}
normalizeOnBlur={data => data.trim()} normalizeOnBlur={(data) => data.trim()}
/> />
</div> </div>
<div className="form__group"> <div className="form__group">
@ -40,15 +40,12 @@ const Form = (props) => {
className="form-control" className="form-control"
placeholder={t('enter_url_or_path_hint')} placeholder={t('enter_url_or_path_hint')}
validate={[required, isValidPath]} validate={[required, isValidPath]}
normalizeOnBlur={data => data.trim()} normalizeOnBlur={(data) => data.trim()}
/> />
</div> </div>
<div className="form__description"> <div className="form__description">
{whitelist ? ( {whitelist ? <Trans>enter_valid_allowlist</Trans>
<Trans>enter_valid_allowlist</Trans> : <Trans>enter_valid_blocklist</Trans>}
) : (
<Trans>enter_valid_blocklist</Trans>
)}
</div> </div>
</div> </div>
<div className="modal-footer"> <div className="modal-footer">
@ -81,7 +78,7 @@ Form.propTypes = {
}; };
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'filterForm', form: 'filterForm',
}), }),

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import { MODAL_TYPE } from '../../helpers/constants'; import { MODAL_TYPE } from '../../helpers/constants';
import Form from './Form'; import Form from './Form';
@ -85,4 +85,4 @@ Modal.propTypes = {
whitelist: PropTypes.bool, whitelist: PropTypes.bool,
}; };
export default withNamespaces()(Modal); export default withTranslation()(Modal);

View File

@ -1,10 +1,12 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { renderInputField, required, domain, answer } from '../../../helpers/form'; import {
renderInputField, required, domain, answer,
} from '../../../helpers/form';
const Form = (props) => { const Form = (props) => {
const { const {
@ -100,7 +102,7 @@ Form.propTypes = {
}; };
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'rewritesForm', form: 'rewritesForm',
enableReinitialize: true, enableReinitialize: true,

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import Form from './Form'; import Form from './Form';
@ -49,4 +49,4 @@ Modal.propTypes = {
processingDelete: PropTypes.bool.isRequired, processingDelete: PropTypes.bool.isRequired,
}; };
export default withNamespaces()(Modal); export default withTranslation()(Modal);

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
class Table extends Component { class Table extends Component {
cellWrap = ({ value }) => ( cellWrap = ({ value }) => (
@ -27,16 +27,15 @@ class Table extends Component {
Header: this.props.t('actions_table_header'), Header: this.props.t('actions_table_header'),
accessor: 'actions', accessor: 'actions',
maxWidth: 100, maxWidth: 100,
Cell: value => ( Cell: (value) => (
<div className="logs__row logs__row--center"> <div className="logs__row logs__row--center">
<button <button
type="button" type="button"
className="btn btn-icon btn-outline-secondary btn-sm" className="btn btn-icon btn-outline-secondary btn-sm"
onClick={() => onClick={() => this.props.handleDelete({
this.props.handleDelete({ answer: value.row.answer,
answer: value.row.answer, domain: value.row.domain,
domain: value.row.domain, })
})
} }
title={this.props.t('delete_table_action')} title={this.props.t('delete_table_action')}
> >
@ -84,4 +83,4 @@ Table.propTypes = {
handleDelete: PropTypes.func.isRequired, handleDelete: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Table); export default withTranslation()(Table);

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import Table from './Table'; import Table from './Table';
import Modal from './Modal'; import Modal from './Modal';
@ -89,4 +89,4 @@ Rewrites.propTypes = {
rewrites: PropTypes.object.isRequired, rewrites: PropTypes.object.isRequired,
}; };
export default withNamespaces()(Rewrites); export default withTranslation()(Rewrites);

View File

@ -1,14 +1,14 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation, Trans } from 'react-i18next';
import CellWrap from '../ui/CellWrap'; import CellWrap from '../ui/CellWrap';
import { MODAL_TYPE } from '../../helpers/constants'; import { MODAL_TYPE } from '../../helpers/constants';
import { formatDetailedDateTime } from '../../helpers/helpers'; import { formatDetailedDateTime } from '../../helpers/helpers';
import { isValidAbsolutePath } from '../../helpers/form'; import { isValidAbsolutePath } from '../../helpers/form';
class Table extends Component { class Table extends Component {
getDateCell = row => CellWrap(row, formatDetailedDateTime); getDateCell = (row) => CellWrap(row, formatDetailedDateTime);
renderCheckbox = ({ original }) => { renderCheckbox = ({ original }) => {
const { processingConfigFilter, toggleFilter } = this.props; const { processingConfigFilter, toggleFilter } = this.props;
@ -49,8 +49,8 @@ class Table extends Component {
minWidth: 200, minWidth: 200,
Cell: ({ value }) => ( Cell: ({ value }) => (
<div className="logs__row logs__row--overflow"> <div className="logs__row logs__row--overflow">
{isValidAbsolutePath(value) ? value : {isValidAbsolutePath(value) ? value
<a : <a
href={value} href={value}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
@ -66,7 +66,7 @@ class Table extends Component {
accessor: 'rulesCount', accessor: 'rulesCount',
className: 'text-center', className: 'text-center',
minWidth: 100, minWidth: 100,
Cell: props => props.value.toLocaleString(), Cell: (props) => props.value.toLocaleString(),
}, },
{ {
Header: <Trans>last_time_updated_table_header</Trans>, Header: <Trans>last_time_updated_table_header</Trans>,
@ -91,11 +91,10 @@ class Table extends Component {
type="button" type="button"
className="btn btn-icon btn-outline-primary btn-sm mr-2" className="btn btn-icon btn-outline-primary btn-sm mr-2"
title={t('edit_table_action')} title={t('edit_table_action')}
onClick={() => onClick={() => toggleFilteringModal({
toggleFilteringModal({ type: MODAL_TYPE.EDIT,
type: MODAL_TYPE.EDIT, url: value,
url: value, })
})
} }
> >
<svg className="icons"> <svg className="icons">
@ -154,4 +153,4 @@ Table.propTypes = {
whitelist: PropTypes.bool, whitelist: PropTypes.bool,
}; };
export default withNamespaces()(Table); export default withTranslation()(Table);

View File

@ -3,7 +3,7 @@ import { NavLink } from 'react-router-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import enhanceWithClickOutside from 'react-click-outside'; import enhanceWithClickOutside from 'react-click-outside';
import classnames from 'classnames'; import classnames from 'classnames';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import { SETTINGS_URLS, FILTERS_URLS, MENU_URLS } from '../../helpers/constants'; import { SETTINGS_URLS, FILTERS_URLS, MENU_URLS } from '../../helpers/constants';
import Dropdown from '../ui/Dropdown'; import Dropdown from '../ui/Dropdown';
@ -51,7 +51,7 @@ class Menu extends Component {
getActiveClassForDropdown = (URLS) => { getActiveClassForDropdown = (URLS) => {
const { pathname } = this.props.location; const { pathname } = this.props.location;
const isActivePage = Object.values(URLS).some(item => item === pathname); const isActivePage = Object.values(URLS).some((item) => item === pathname);
return isActivePage ? 'active' : ''; return isActivePage ? 'active' : '';
}; };
@ -77,21 +77,20 @@ class Menu extends Component {
getDropdown = ({ getDropdown = ({
label, order, URLS, icon, ITEMS, label, order, URLS, icon, ITEMS,
}) => }) => (
(
<Dropdown <Dropdown
label={this.props.t(label)} label={this.props.t(label)}
baseClassName={`dropdown nav-item order-${order}`} baseClassName={`dropdown nav-item order-${order}`}
controlClassName={`nav-link ${this.getActiveClassForDropdown(URLS)}`} controlClassName={`nav-link ${this.getActiveClassForDropdown(URLS)}`}
icon={icon}> icon={icon}>
{ITEMS.map(item => ( {ITEMS.map((item) => (
this.getNavLink({ this.getNavLink({
...item, ...item,
order, order,
className: 'dropdown-item', className: 'dropdown-item',
})))} })))}
</Dropdown> </Dropdown>
); );
render() { render() {
const menuClass = classnames({ const menuClass = classnames({
@ -102,7 +101,7 @@ class Menu extends Component {
<Fragment> <Fragment>
<div className={menuClass}> <div className={menuClass}>
<ul className="nav nav-tabs border-0 flex-column flex-lg-row flex-nowrap"> <ul className="nav nav-tabs border-0 flex-column flex-lg-row flex-nowrap">
{MENU_ITEMS.map(item => ( {MENU_ITEMS.map((item) => (
<li <li
className={`nav-item order-${item.order}`} className={`nav-item order-${item.order}`}
key={item.text} key={item.text}
@ -139,4 +138,4 @@ Menu.propTypes = {
t: PropTypes.func, t: PropTypes.func,
}; };
export default withNamespaces()(enhanceWithClickOutside(Menu)); export default withTranslation()(enhanceWithClickOutside(Menu));

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import Menu from './Menu'; import Menu from './Menu';
import logo from '../ui/svg/logo.svg'; import logo from '../ui/svg/logo.svg';
@ -14,7 +14,7 @@ class Header extends Component {
}; };
toggleMenuOpen = () => { toggleMenuOpen = () => {
this.setState(prevState => ({ isMenuOpen: !prevState.isMenuOpen })); this.setState((prevState) => ({ isMenuOpen: !prevState.isMenuOpen }));
}; };
closeMenu = () => { closeMenu = () => {
@ -59,8 +59,8 @@ class Header extends Component {
/> />
<div className="header__column"> <div className="header__column">
<div className="header__right"> <div className="header__right">
{!dashboard.processingProfile && dashboard.name && {!dashboard.processingProfile && dashboard.name
<a href="control/logout" className="btn btn-sm btn-outline-secondary"> && <a href="control/logout" className="btn btn-sm btn-outline-secondary">
<Trans>sign_out</Trans> <Trans>sign_out</Trans>
</a> </a>
} }
@ -80,4 +80,4 @@ Header.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Header); export default withTranslation()(Header);

View File

@ -1,7 +1,7 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { renderInputField } from '../../../helpers/form'; import { renderInputField } from '../../../helpers/form';
@ -18,27 +18,40 @@ const renderFilterField = ({
autoComplete, autoComplete,
tooltip, tooltip,
meta: { touched, error }, meta: { touched, error },
}) => ( }) => <Fragment>
<Fragment> <div className="logs__input-wrap">
<div className="logs__input-wrap"> <input
<input {...input}
{...input} id={id}
id={id} placeholder={placeholder}
placeholder={placeholder} type={type}
type={type} className={className}
className={className} disabled={disabled}
disabled={disabled} autoComplete={autoComplete}
autoComplete={autoComplete} />
/> <span className="logs__notice">
<span className="logs__notice">
<Tooltip text={tooltip} type='tooltip-custom--logs' /> <Tooltip text={tooltip} type='tooltip-custom--logs' />
</span> </span>
{!disabled && {!disabled
touched && && touched
(error && <span className="form__message form__message--error">{error}</span>)} && (error && <span className="form__message form__message--error">{error}</span>)}
</div> </div>
</Fragment> </Fragment>;
);
renderFilterField.propTypes = {
input: PropTypes.object.isRequired,
id: PropTypes.string.isRequired,
className: PropTypes.string,
placeholder: PropTypes.string,
type: PropTypes.string,
disabled: PropTypes.string,
autoComplete: PropTypes.string,
tooltip: PropTypes.string,
meta: PropTypes.shape({
touched: PropTypes.bool,
error: PropTypes.object,
}).isRequired,
};
const Form = (props) => { const Form = (props) => {
const { const {
@ -79,10 +92,10 @@ const Form = (props) => {
className="form-control custom-select" className="form-control custom-select"
> >
<option value={RESPONSE_FILTER.ALL}> <option value={RESPONSE_FILTER.ALL}>
<Trans>show_all_filter_type</Trans> {t('show_all_filter_type')}
</option> </option>
<option value={RESPONSE_FILTER.FILTERED}> <option value={RESPONSE_FILTER.FILTERED}>
<Trans>show_filtered_type</Trans> {t('show_filtered_type')}
</option> </option>
</Field> </Field>
</div> </div>
@ -109,7 +122,7 @@ Form.propTypes = {
}; };
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'logsFilterForm', form: 'logsFilterForm',
}), }),

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import escapeRegExp from 'lodash/escapeRegExp'; import escapeRegExp from 'lodash/escapeRegExp';
import endsWith from 'lodash/endsWith'; import endsWith from 'lodash/endsWith';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import { HashLink as Link } from 'react-router-hash-link'; import { HashLink as Link } from 'react-router-hash-link';
import { import {
@ -17,7 +17,9 @@ import {
checkBlackList, checkBlackList,
checkBlockedService, checkBlockedService,
} from '../../helpers/helpers'; } from '../../helpers/helpers';
import { SERVICES, TABLE_DEFAULT_PAGE_SIZE, CUSTOM_FILTERING_RULES_ID, FILTERED } from '../../helpers/constants'; import {
SERVICES, TABLE_DEFAULT_PAGE_SIZE, CUSTOM_FILTERING_RULES_ID, FILTERED,
} from '../../helpers/constants';
import { getTrackerData } from '../../helpers/trackers/trackers'; import { getTrackerData } from '../../helpers/trackers/trackers';
import { formatClientCell } from '../../helpers/formatClientCell'; import { formatClientCell } from '../../helpers/formatClientCell';
@ -54,8 +56,8 @@ class Logs extends Component {
window.location.reload(); window.location.reload();
}; };
renderTooltip = (isFiltered, rule, filter, service) => renderTooltip = (isFiltered, rule, filter, service) => isFiltered
isFiltered && <PopoverFiltered rule={rule} filter={filter} service={service} />; && <PopoverFiltered rule={rule} filter={filter} service={service} />;
renderResponseList = (response, status) => { renderResponseList = (response, status) => {
if (response.length > 0) { if (response.length > 0) {
@ -116,7 +118,7 @@ class Logs extends Component {
); );
} }
getDateCell = row => CellWrap( getDateCell = (row) => CellWrap(
row, row,
(isToday(row.value) ? formatTime : formatDateTime), (isToday(row.value) ? formatTime : formatDateTime),
formatDateTime, formatDateTime,
@ -134,7 +136,7 @@ class Logs extends Component {
); );
}; };
normalizeResponse = response => ( normalizeResponse = (response) => (
response.map((response) => { response.map((response) => {
const { value, type, ttl } = response; const { value, type, ttl } = response;
return `${type}: ${value} (ttl=${ttl})`; return `${type}: ${value} (ttl=${ttl})`;
@ -146,8 +148,8 @@ class Logs extends Component {
return t('custom_filter_rules'); return t('custom_filter_rules');
} }
const filter = filters.find(filter => filter.id === filterId) const filter = filters.find((filter) => filter.id === filterId)
|| whitelistFilters.find(filter => filter.id === filterId); || whitelistFilters.find((filter) => filter.id === filterId);
let filterName = ''; let filterName = '';
if (filter) { if (filter) {
@ -178,7 +180,7 @@ class Logs extends Component {
const filterKey = reason.replace(FILTERED, ''); const filterKey = reason.replace(FILTERED, '');
const parsedFilteredReason = t('query_log_filtered', { filter: filterKey }); const parsedFilteredReason = t('query_log_filtered', { filter: filterKey });
const currentService = SERVICES.find(service => service.id === original.serviceName); const currentService = SERVICES.find((service) => service.id === original.serviceName);
const serviceName = currentService && currentService.name; const serviceName = currentService && currentService.name;
const filterName = this.getFilterName(filters, whitelistFilters, filterId, t); const filterName = this.getFilterName(filters, whitelistFilters, filterId, t);
@ -378,11 +380,11 @@ class Logs extends Component {
return { return {
className: 'red', className: 'red',
}; };
} else if (checkWhiteList(reason)) { } if (checkWhiteList(reason)) {
return { return {
className: 'green', className: 'green',
}; };
} else if (checkRewrite(reason) || checkRewriteHosts(reason)) { } if (checkRewrite(reason) || checkRewriteHosts(reason)) {
return { return {
className: 'blue', className: 'blue',
}; };
@ -467,4 +469,4 @@ Logs.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Logs); export default withTranslation()(Logs);

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import Card from '../../ui/Card'; import Card from '../../ui/Card';
@ -38,7 +38,7 @@ class AutoClients extends Component {
}, },
{ {
Header: this.props.t('requests_count'), Header: this.props.t('requests_count'),
accessor: row => this.props.normalizedTopClients.auto[row.ip] || 0, accessor: (row) => this.props.normalizedTopClients.auto[row.ip] || 0,
sortMethod: (a, b) => b - a, sortMethod: (a, b) => b - a,
id: 'statistics', id: 'statistics',
minWidth: COLUMN_MIN_WIDTH, minWidth: COLUMN_MIN_WIDTH,
@ -101,4 +101,4 @@ AutoClients.propTypes = {
normalizedTopClients: PropTypes.object.isRequired, normalizedTopClients: PropTypes.object.isRequired,
}; };
export default withNamespaces()(AutoClients); export default withTranslation()(AutoClients);

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import { MODAL_TYPE } from '../../../helpers/constants'; import { MODAL_TYPE } from '../../../helpers/constants';
@ -25,7 +25,7 @@ class ClientsTable extends Component {
if (values.blocked_services) { if (values.blocked_services) {
config.blocked_services = Object config.blocked_services = Object
.keys(values.blocked_services) .keys(values.blocked_services)
.filter(service => values.blocked_services[service]); .filter((service) => values.blocked_services[service]);
} }
if (values.upstreams && typeof values.upstreams === 'string') { if (values.upstreams && typeof values.upstreams === 'string') {
@ -35,7 +35,7 @@ class ClientsTable extends Component {
} }
if (values.tags) { if (values.tags) {
config.tags = values.tags.map(tag => tag.value); config.tags = values.tags.map((tag) => tag.value);
} else { } else {
config.tags = []; config.tags = [];
} }
@ -48,12 +48,12 @@ class ClientsTable extends Component {
} }
}; };
getOptionsWithLabels = options => ( getOptionsWithLabels = (options) => (
options.map(option => ({ value: option, label: option })) options.map((option) => ({ value: option, label: option }))
); );
getClient = (name, clients) => { getClient = (name, clients) => {
const client = clients.find(item => name === item.name); const client = clients.find((item) => name === item.name);
if (client) { if (client) {
const { const {
@ -93,7 +93,7 @@ class ClientsTable extends Component {
return ( return (
<div className="logs__row logs__row--overflow"> <div className="logs__row logs__row--overflow">
<span className="logs__text"> <span className="logs__text">
{value.map(address => ( {value.map((address) => (
<div key={address} title={address}> <div key={address} title={address}>
{address} {address}
</div> </div>
@ -141,7 +141,7 @@ class ClientsTable extends Component {
return ( return (
<div className="logs__row logs__row--icons"> <div className="logs__row logs__row--icons">
{value && value.length > 0 {value && value.length > 0
? value.map(service => ( ? value.map((service) => (
<svg <svg
className="service__icon service__icon--table" className="service__icon service__icon--table"
title={service} title={service}
@ -187,7 +187,7 @@ class ClientsTable extends Component {
return ( return (
<div className="logs__row logs__row--overflow"> <div className="logs__row logs__row--overflow">
<span className="logs__text"> <span className="logs__text">
{value.map(tag => ( {value.map((tag) => (
<div key={tag} title={tag} className="small"> <div key={tag} title={tag} className="small">
{tag} {tag}
</div> </div>
@ -200,7 +200,7 @@ class ClientsTable extends Component {
{ {
Header: this.props.t('requests_count'), Header: this.props.t('requests_count'),
id: 'statistics', id: 'statistics',
accessor: row => this.props.normalizedTopClients.configured[row.name] || 0, accessor: (row) => this.props.normalizedTopClients.configured[row.name] || 0,
sortMethod: (a, b) => b - a, sortMethod: (a, b) => b - a,
minWidth: 120, minWidth: 120,
Cell: CellWrap, Cell: CellWrap,
@ -220,11 +220,10 @@ class ClientsTable extends Component {
<button <button
type="button" type="button"
className="btn btn-icon btn-outline-primary btn-sm mr-2" className="btn btn-icon btn-outline-primary btn-sm mr-2"
onClick={() => onClick={() => toggleClientModal({
toggleClientModal({ type: MODAL_TYPE.EDIT,
type: MODAL_TYPE.EDIT, name: clientName,
name: clientName, })
})
} }
disabled={processingUpdating} disabled={processingUpdating}
title={t('edit_table_action')} title={t('edit_table_action')}
@ -337,4 +336,4 @@ ClientsTable.propTypes = {
supportedTags: PropTypes.array.isRequired, supportedTags: PropTypes.array.isRequired,
}; };
export default withNamespaces()(ClientsTable); export default withTranslation()(ClientsTable);

View File

@ -1,8 +1,10 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, FieldArray, reduxForm, formValueSelector } from 'redux-form'; import {
import { Trans, withNamespaces } from 'react-i18next'; Field, FieldArray, reduxForm, formValueSelector,
} from 'redux-form';
import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import Select from 'react-select'; import Select from 'react-select';
@ -62,40 +64,39 @@ const validate = (values) => {
}; };
const renderFieldsWrapper = (placeholder, buttonTitle) => const renderFieldsWrapper = (placeholder, buttonTitle) => function cell(row) {
function cell(row) { const {
const { fields,
fields, } = row;
} = row; return (
return ( <div className="form__group">
<div className="form__group"> {fields.map((ip, index) => (
{fields.map((ip, index) => ( <div key={index} className="mb-1">
<div key={index} className="mb-1"> <Field
<Field name={ip}
name={ip} component={renderGroupField}
component={renderGroupField} type="text"
type="text" className="form-control"
className="form-control" placeholder={placeholder}
placeholder={placeholder} isActionAvailable={index !== 0}
isActionAvailable={index !== 0} removeField={() => fields.remove(index)}
removeField={() => fields.remove(index)} normalizeOnBlur={(data) => data.trim()}
normalizeOnBlur={data => data.trim()} />
/> </div>
</div> ))}
))} <button
<button type="button"
type="button" className="btn btn-link btn-block btn-sm"
className="btn btn-link btn-block btn-sm" onClick={() => fields.push()}
onClick={() => fields.push()} title={buttonTitle}
title={buttonTitle} >
> <svg className="icon icon--close">
<svg className="icon icon--close"> <use xlinkHref="#plus" />
<use xlinkHref="#plus" /> </svg>
</svg> </button>
</button> </div>
</div> );
); };
};
// Should create function outside of component to prevent component re-renders // Should create function outside of component to prevent component re-renders
const renderFields = renderFieldsWrapper(i18n.t('form_enter_id'), i18n.t('form_add_id')); const renderFields = renderFieldsWrapper(i18n.t('form_enter_id'), i18n.t('form_add_id'));
@ -109,7 +110,7 @@ const renderMultiselect = (props) => {
options={options} options={options}
className="basic-multi-select" className="basic-multi-select"
classNamePrefix="select" classNamePrefix="select"
onChange={value => input.onChange(value)} onChange={(value) => input.onChange(value)}
onBlur={() => input.onBlur(input.value)} onBlur={() => input.onBlur(input.value)}
placeholder={placeholder} placeholder={placeholder}
blurInputOnSelect={false} blurInputOnSelect={false}
@ -118,6 +119,12 @@ const renderMultiselect = (props) => {
); );
}; };
renderMultiselect.propTypes = {
input: PropTypes.object.isRequired,
placeholder: PropTypes.string,
options: PropTypes.object,
};
let Form = (props) => { let Form = (props) => {
const { const {
t, t,
@ -147,7 +154,7 @@ let Form = (props) => {
type="text" type="text"
className="form-control" className="form-control"
placeholder={t('form_client_name')} placeholder={t('form_client_name')}
normalizeOnBlur={data => data.trim()} normalizeOnBlur={(data) => data.trim()}
/> />
</div> </div>
@ -159,7 +166,8 @@ let Form = (props) => {
</div> </div>
<div className="form__desc mt-0 mb-2"> <div className="form__desc mt-0 mb-2">
<Trans components={[ <Trans components={[
<a href="https://github.com/AdguardTeam/AdGuardHome/wiki/Hosts-Blocklists#ctag" key="0">link</a>, <a href="https://github.com/AdguardTeam/AdGuardHome/wiki/Hosts-Blocklists#ctag"
key="0">link</a>,
]}> ]}>
tags_desc tags_desc
</Trans> </Trans>
@ -201,7 +209,7 @@ let Form = (props) => {
<Tabs controlClass="form"> <Tabs controlClass="form">
<div label="settings" title={props.t('main_settings')}> <div label="settings" title={props.t('main_settings')}>
{settingsCheckboxes.map(setting => ( {settingsCheckboxes.map((setting) => (
<div className="form__group" key={setting.name}> <div className="form__group" key={setting.name}>
<Field <Field
name={setting.name} name={setting.name}
@ -249,7 +257,7 @@ let Form = (props) => {
</div> </div>
</div> </div>
<div className="services"> <div className="services">
{SERVICES.map(service => ( {SERVICES.map((service) => (
<Field <Field
key={service.id} key={service.id}
icon={`service_${service.id}`} icon={`service_${service.id}`}
@ -299,11 +307,11 @@ let Form = (props) => {
type="submit" type="submit"
className="btn btn-success btn-standard" className="btn btn-success btn-standard"
disabled={ disabled={
submitting || submitting
invalid || || invalid
pristine || || pristine
processingAdding || || processingAdding
processingUpdating || processingUpdating
} }
> >
<Trans>save_btn</Trans> <Trans>save_btn</Trans>
@ -342,7 +350,7 @@ Form = connect((state) => {
})(Form); })(Form);
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'clientForm', form: 'clientForm',
enableReinitialize: true, enableReinitialize: true,

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import { MODAL_TYPE } from '../../../helpers/constants'; import { MODAL_TYPE } from '../../../helpers/constants';
@ -81,4 +81,4 @@ Modal.propTypes = {
tagsOptions: PropTypes.array.isRequired, tagsOptions: PropTypes.array.isRequired,
}; };
export default withNamespaces()(Modal); export default withTranslation()(Modal);

View File

@ -1,5 +1,5 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ClientsTable from './ClientsTable'; import ClientsTable from './ClientsTable';
@ -72,4 +72,4 @@ Clients.propTypes = {
getStats: PropTypes.func.isRequired, getStats: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Clients); export default withTranslation()(Clients);

View File

@ -29,15 +29,14 @@ const getFormattedWhois = (value, t) => {
return ''; return '';
}; };
const whoisCell = t => const whoisCell = (t) => function cell(row) {
function cell(row) { const { value } = row;
const { value } = row;
return ( return (
<div className="logs__row logs__row--overflow"> <div className="logs__row logs__row--overflow">
<span className="logs__text logs__text--wrap">{getFormattedWhois(value, t)}</span> <span className="logs__text logs__text--wrap">{getFormattedWhois(value, t)}</span>
</div> </div>
); );
}; };
export default whoisCell; export default whoisCell;

View File

@ -2,16 +2,18 @@ import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm, formValueSelector } from 'redux-form'; import { Field, reduxForm, formValueSelector } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { renderInputField, required, ipv4, isPositive, toNumber } from '../../../helpers/form'; import {
renderInputField, required, ipv4, isPositive, toNumber,
} from '../../../helpers/form';
const renderInterfaces = (interfaces => ( const renderInterfaces = ((interfaces) => (
Object.keys(interfaces).map((item) => { Object.keys(interfaces).map((item) => {
const option = interfaces[item]; const option = interfaces[item];
const { name } = option; const { name } = option;
const onlyIPv6 = option.ip_addresses.every(ip => ip.includes(':')); const onlyIPv6 = option.ip_addresses.every((ip) => ip.includes(':'));
let interfaceIP = option.ip_addresses[0]; let interfaceIP = option.ip_addresses[0];
if (!onlyIPv6) { if (!onlyIPv6) {
@ -30,7 +32,7 @@ const renderInterfaces = (interfaces => (
}) })
)); ));
const renderInterfaceValues = (interfaceValues => ( const renderInterfaceValues = ((interfaceValues) => (
<ul className="list-unstyled mt-1 mb-0"> <ul className="list-unstyled mt-1 mb-0">
<li> <li>
<span className="interface__title">MTU: </span> <span className="interface__title">MTU: </span>
@ -44,7 +46,7 @@ const renderInterfaceValues = (interfaceValues => (
<span className="interface__title"><Trans>dhcp_ip_addresses</Trans>: </span> <span className="interface__title"><Trans>dhcp_ip_addresses</Trans>: </span>
{ {
interfaceValues.ip_addresses interfaceValues.ip_addresses
.map(ip => <span key={ip} className="interface__ip">{ip}</span>) .map((ip) => <span key={ip} className="interface__ip">{ip}</span>)
} }
</li> </li>
</ul> </ul>
@ -62,7 +64,7 @@ const clearFields = (change, resetDhcp, t) => {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (window.confirm(t('dhcp_reset'))) { if (window.confirm(t('dhcp_reset'))) {
Object.keys(fields).forEach(field => change(field, fields[field])); Object.keys(fields).forEach((field) => change(field, fields[field]));
resetDhcp(); resetDhcp();
} }
}; };
@ -84,8 +86,8 @@ let Form = (props) => {
return ( return (
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
{!processingInterfaces && interfaces && {!processingInterfaces && interfaces
<div className="row"> && <div className="row">
<div className="col-sm-12 col-md-6"> <div className="col-sm-12 col-md-6">
<div className="form__group form__group--settings"> <div className="form__group form__group--settings">
<label>{t('dhcp_interface_select')}</label> <label>{t('dhcp_interface_select')}</label>
@ -102,10 +104,10 @@ let Form = (props) => {
</Field> </Field>
</div> </div>
</div> </div>
{interfaceValue && {interfaceValue
<div className="col-sm-12 col-md-6"> && <div className="col-sm-12 col-md-6">
{interfaces[interfaceValue] && {interfaces[interfaceValue]
renderInterfaceValues(interfaces[interfaceValue])} && renderInterfaceValues(interfaces[interfaceValue])}
</div> </div>
} }
</div> </div>
@ -229,6 +231,6 @@ Form = connect((state) => {
})(Form); })(Form);
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ form: 'dhcpForm' }), reduxForm({ form: 'dhcpForm' }),
])(Form); ])(Form);

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import { SMALL_TABLE_DEFAULT_PAGE_SIZE } from '../../../helpers/constants'; import { SMALL_TABLE_DEFAULT_PAGE_SIZE } from '../../../helpers/constants';
class Leases extends Component { class Leases extends Component {
@ -53,4 +53,4 @@ Leases.propTypes = {
t: PropTypes.func, t: PropTypes.func,
}; };
export default withNamespaces()(Leases); export default withTranslation()(Leases);

View File

@ -1,10 +1,12 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { renderInputField, ipv4, mac, required } from '../../../../helpers/form'; import {
renderInputField, ipv4, mac, required,
} from '../../../../helpers/form';
const Form = (props) => { const Form = (props) => {
const { const {
@ -91,6 +93,6 @@ Form.propTypes = {
}; };
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ form: 'leaseForm' }), reduxForm({ form: 'leaseForm' }),
])(Form); ])(Form);

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import Form from './Form'; import Form from './Form';
@ -46,4 +46,4 @@ Modal.propTypes = {
processingAdding: PropTypes.bool.isRequired, processingAdding: PropTypes.bool.isRequired,
}; };
export default withNamespaces()(Modal); export default withTranslation()(Modal);

View File

@ -1,7 +1,7 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import { SMALL_TABLE_DEFAULT_PAGE_SIZE } from '../../../../helpers/constants'; import { SMALL_TABLE_DEFAULT_PAGE_SIZE } from '../../../../helpers/constants';
import Modal from './Modal'; import Modal from './Modal';
@ -70,8 +70,7 @@ class StaticLeases extends Component {
className="btn btn-icon btn-outline-secondary btn-sm" className="btn btn-icon btn-outline-secondary btn-sm"
title={t('delete_table_action')} title={t('delete_table_action')}
disabled={processingDeleting} disabled={processingDeleting}
onClick={() => onClick={() => this.handleDelete(ip, mac, hostname)
this.handleDelete(ip, mac, hostname)
} }
> >
<svg className="icons"> <svg className="icons">
@ -112,4 +111,4 @@ StaticLeases.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(StaticLeases); export default withTranslation()(StaticLeases);

View File

@ -1,7 +1,7 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import { DHCP_STATUS_RESPONSE } from '../../../helpers/constants'; import { DHCP_STATUS_RESPONSE } from '../../../helpers/constants';
import Form from './Form'; import Form from './Form';
@ -32,8 +32,8 @@ class Dhcp extends Component {
const { const {
config, check, processingDhcp, processingConfig, config, check, processingDhcp, processingConfig,
} = this.props.dhcp; } = this.props.dhcp;
const otherDhcpFound = const otherDhcpFound = check && check.otherServer
check && check.otherServer && check.otherServer.found === DHCP_STATUS_RESPONSE.YES; && check.otherServer.found === DHCP_STATUS_RESPONSE.YES;
const filledConfig = Object.keys(config).every((key) => { const filledConfig = Object.keys(config).every((key) => {
if (key === 'enabled' || key === 'icmp_timeout_msec') { if (key === 'enabled' || key === 'icmp_timeout_msec') {
return true; return true;
@ -127,10 +127,10 @@ class Dhcp extends Component {
<hr className="mt-4 mb-4" /> <hr className="mt-4 mb-4" />
</Fragment> </Fragment>
); );
} else if ( } if (
check.staticIP.static === DHCP_STATUS_RESPONSE.NO && check.staticIP.static === DHCP_STATUS_RESPONSE.NO
check.staticIP.ip && && check.staticIP.ip
interfaceName && interfaceName
) { ) {
return ( return (
<Fragment> <Fragment>
@ -278,4 +278,4 @@ Dhcp.propTypes = {
resetDhcp: PropTypes.func.isRequired, resetDhcp: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Dhcp); export default withTranslation()(Dhcp);

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { renderTextareaField } from '../../../../helpers/form'; import { renderTextareaField } from '../../../../helpers/form';
@ -82,4 +82,4 @@ Form.propTypes = {
textarea: PropTypes.bool, textarea: PropTypes.bool,
}; };
export default flow([withNamespaces(), reduxForm({ form: 'accessForm' })])(Form); export default flow([withTranslation(), reduxForm({ form: 'accessForm' })])(Form);

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import Form from './Form'; import Form from './Form';
import Card from '../../../ui/Card'; import Card from '../../../ui/Card';
@ -37,4 +37,4 @@ Access.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Access); export default withTranslation()(Access);

View File

@ -2,7 +2,7 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Field, reduxForm, formValueSelector } from 'redux-form'; import { Field, reduxForm, formValueSelector } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { import {
@ -45,7 +45,7 @@ const customIps = [{
}]; }];
const getFields = (processing, t) => Object.values(BLOCKING_MODES) const getFields = (processing, t) => Object.values(BLOCKING_MODES)
.map(mode => ( .map((mode) => (
<Field <Field
key={mode} key={mode}
name="blocking_mode" name="blocking_mode"
@ -59,8 +59,7 @@ const getFields = (processing, t) => Object.values(BLOCKING_MODES)
let Form = ({ let Form = ({
handleSubmit, submitting, invalid, processing, blockingMode, t, handleSubmit, submitting, invalid, processing, blockingMode, t,
}) => }) => <form onSubmit={handleSubmit}>
<form onSubmit={handleSubmit}>
<div className="row"> <div className="row">
<div className="col-12 col-sm-6"> <div className="col-12 col-sm-6">
<div className="form__group form__group--settings"> <div className="form__group form__group--settings">
@ -82,8 +81,7 @@ let Form = ({
/> />
</div> </div>
</div> </div>
{checkboxes.map(({ name, placeholder, subtitle }) => {checkboxes.map(({ name, placeholder, subtitle }) => <div className="col-12" key={name}>
<div className="col-12" key={name}>
<div className="form__group form__group--settings"> <div className="form__group form__group--settings">
<Field <Field
name={name} name={name}
@ -102,7 +100,7 @@ let Form = ({
</label> </label>
<div className="form__desc form__desc--top"> <div className="form__desc form__desc--top">
{Object.values(BLOCKING_MODES) {Object.values(BLOCKING_MODES)
.map(mode => ( .map((mode) => (
<li key={mode}> <li key={mode}>
<Trans>{`blocking_mode_${mode}`}</Trans> <Trans>{`blocking_mode_${mode}`}</Trans>
</li> </li>
@ -167,7 +165,7 @@ Form = connect((state) => {
})(Form); })(Form);
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'blockingModeForm', form: 'blockingModeForm',
}), }),

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import Card from '../../../ui/Card'; import Card from '../../../ui/Card';
import Form from './Form'; import Form from './Form';
@ -52,4 +52,4 @@ Config.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Config); export default withTranslation()(Config);

View File

@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
const Examples = props => ( const Examples = (props) => (
<div className="list leading-loose"> <div className="list leading-loose">
<p> <p>
<Trans <Trans
@ -128,4 +128,4 @@ Examples.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Examples); export default withTranslation()(Examples);

View File

@ -2,7 +2,7 @@ import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm, formValueSelector } from 'redux-form'; import { Field, reduxForm, formValueSelector } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import classnames from 'classnames'; import classnames from 'classnames';
@ -107,11 +107,10 @@ let Form = (props) => {
<button <button
type="button" type="button"
className={testButtonClass} className={testButtonClass}
onClick={() => onClick={() => testUpstream({
testUpstream({ upstream_dns,
upstream_dns, bootstrap_dns,
bootstrap_dns, })
})
} }
disabled={!upstream_dns || processingTestUpstream} disabled={!upstream_dns || processingTestUpstream}
> >
@ -164,7 +163,7 @@ Form = connect((state) => {
})(Form); })(Form);
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'upstreamForm', form: 'upstreamForm',
}), }),

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import Form from './Form'; import Form from './Form';
import Card from '../../../ui/Card'; import Card from '../../../ui/Card';
@ -62,4 +62,4 @@ Upstream.propTypes = {
setDnsConfig: PropTypes.func.isRequired, setDnsConfig: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Upstream); export default withTranslation()(Upstream);

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import Upstream from './Upstream'; import Upstream from './Upstream';
import Access from './Access'; import Access from './Access';
@ -30,9 +30,9 @@ class Dns extends Component {
return ( return (
<Fragment> <Fragment>
<PageTitle title={t('dns_settings')} /> <PageTitle title={t('dns_settings')} />
{isDataLoading ? {isDataLoading
<Loading /> : ? <Loading />
<Fragment> : <Fragment>
<Upstream <Upstream
processingTestUpstream={settings.processingTestUpstream} processingTestUpstream={settings.processingTestUpstream}
testUpstream={testUpstream} testUpstream={testUpstream}
@ -62,4 +62,4 @@ Dns.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Dns); export default withTranslation()(Dns);

View File

@ -1,6 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation, Trans } from 'react-i18next';
import format from 'date-fns/format'; import format from 'date-fns/format';
import { EMPTY_DATE } from '../../../helpers/constants'; import { EMPTY_DATE } from '../../../helpers/constants';
@ -68,4 +68,4 @@ CertificateStatus.propTypes = {
dnsNames: PropTypes.string, dnsNames: PropTypes.string,
}; };
export default withNamespaces()(CertificateStatus); export default withTranslation()(CertificateStatus);

View File

@ -2,7 +2,7 @@ import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm, formValueSelector } from 'redux-form'; import { Field, reduxForm, formValueSelector } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { import {
@ -45,7 +45,7 @@ const clearFields = (change, setTlsConfig, t) => {
}; };
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (window.confirm(t('encryption_reset'))) { if (window.confirm(t('encryption_reset'))) {
Object.keys(fields).forEach(field => change(field, fields[field])); Object.keys(fields).forEach((field) => change(field, fields[field]));
setTlsConfig(fields); setTlsConfig(fields);
} }
}; };
@ -80,14 +80,13 @@ let Form = (props) => {
privateKeySource, privateKeySource,
} = props; } = props;
const isSavingDisabled = const isSavingDisabled = invalid
invalid || || submitting
submitting || || processingConfig
processingConfig || || processingValidate
processingValidate || || !valid_key
!valid_key || || !valid_cert
!valid_cert || || !valid_pair;
!valid_pair;
return ( return (
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
@ -417,7 +416,7 @@ Form = connect((state) => {
})(Form); })(Form);
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'encryptionForm', form: 'encryptionForm',
validate, validate,

View File

@ -1,6 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation, Trans } from 'react-i18next';
const KeyStatus = ({ validKey, keyType }) => ( const KeyStatus = ({ validKey, keyType }) => (
<Fragment> <Fragment>
@ -28,4 +28,4 @@ KeyStatus.propTypes = {
keyType: PropTypes.string.isRequired, keyType: PropTypes.string.isRequired,
}; };
export default withNamespaces()(KeyStatus); export default withTranslation()(KeyStatus);

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import { DEBOUNCE_TIMEOUT, ENCRYPTION_SOURCE } from '../../../helpers/constants'; import { DEBOUNCE_TIMEOUT, ENCRYPTION_SOURCE } from '../../../helpers/constants';
@ -115,4 +115,4 @@ Encryption.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Encryption); export default withTranslation()(Encryption);

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { renderSelectField, toNumber } from '../../../helpers/form'; import { renderSelectField, toNumber } from '../../../helpers/form';
@ -10,7 +10,7 @@ import { FILTERS_INTERVALS_HOURS } from '../../../helpers/constants';
const getTitleForInterval = (interval, t) => { const getTitleForInterval = (interval, t) => {
if (interval === 0) { if (interval === 0) {
return t('disabled'); return t('disabled');
} else if (interval === 72 || interval === 168) { } if (interval === 72 || interval === 168) {
return t('interval_days', { count: interval / 24 }); return t('interval_days', { count: interval / 24 });
} }
@ -26,7 +26,7 @@ const getIntervalSelect = (processing, t, handleChange, toNumber) => (
normalize={toNumber} normalize={toNumber}
disabled={processing} disabled={processing}
> >
{FILTERS_INTERVALS_HOURS.map(interval => ( {FILTERS_INTERVALS_HOURS.map((interval) => (
<option value={interval} key={interval}> <option value={interval} key={interval}>
{getTitleForInterval(interval, t)} {getTitleForInterval(interval, t)}
</option> </option>
@ -81,7 +81,7 @@ Form.propTypes = {
}; };
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'filterConfigForm', form: 'filterConfigForm',
}), }),

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import { DEBOUNCE_TIMEOUT } from '../../../helpers/constants'; import { DEBOUNCE_TIMEOUT } from '../../../helpers/constants';
@ -33,4 +33,4 @@ FiltersConfig.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(FiltersConfig); export default withTranslation()(FiltersConfig);

View File

@ -1,18 +1,16 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { renderSelectField, renderRadioField, toNumber } from '../../../helpers/form'; import { renderSelectField, renderRadioField, toNumber } from '../../../helpers/form';
import { QUERY_LOG_INTERVALS_DAYS } from '../../../helpers/constants'; import { QUERY_LOG_INTERVALS_DAYS } from '../../../helpers/constants';
const getIntervalFields = (processing, t, toNumber) => const getIntervalFields = (processing, t, toNumber) => QUERY_LOG_INTERVALS_DAYS.map((interval) => {
QUERY_LOG_INTERVALS_DAYS.map((interval) => { const title = interval === 1 ? t('interval_24_hour') : t('interval_days', { count: interval });
const title =
interval === 1 ? t('interval_24_hour') : t('interval_days', { count: interval });
return ( return (
<Field <Field
key={interval} key={interval}
name="interval" name="interval"
@ -23,8 +21,8 @@ const getIntervalFields = (processing, t, toNumber) =>
normalize={toNumber} normalize={toNumber}
disabled={processing} disabled={processing}
/> />
); );
}); });
const Form = (props) => { const Form = (props) => {
const { const {
@ -92,7 +90,7 @@ Form.propTypes = {
}; };
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'logConfigForm', form: 'logConfigForm',
}), }),

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import Card from '../../ui/Card'; import Card from '../../ui/Card';
import Form from './Form'; import Form from './Form';
@ -68,4 +68,4 @@ LogsConfig.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(LogsConfig); export default withTranslation()(LogsConfig);

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { toggleAllServices } from '../../../helpers/helpers'; import { toggleAllServices } from '../../../helpers/helpers';
@ -44,7 +44,7 @@ const Form = (props) => {
</div> </div>
</div> </div>
<div className="services"> <div className="services">
{SERVICES.map(service => ( {SERVICES.map((service) => (
<Field <Field
key={service.id} key={service.id}
icon={`service_${service.id}`} icon={`service_${service.id}`}
@ -82,7 +82,7 @@ Form.propTypes = {
}; };
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'servicesForm', form: 'servicesForm',
enableReinitialize: true, enableReinitialize: true,

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import Form from './Form'; import Form from './Form';
import Card from '../../ui/Card'; import Card from '../../ui/Card';
@ -12,7 +12,7 @@ class Services extends Component {
if (values && values.blocked_services) { if (values && values.blocked_services) {
const blocked_services = Object const blocked_services = Object
.keys(values.blocked_services) .keys(values.blocked_services)
.filter(service => values.blocked_services[service]); .filter((service) => values.blocked_services[service]);
config = blocked_services; config = blocked_services;
} }
@ -66,4 +66,4 @@ Services.propTypes = {
setBlockedServices: PropTypes.func.isRequired, setBlockedServices: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Services); export default withTranslation()(Services);

View File

@ -1,18 +1,16 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form'; import { Field, reduxForm } from 'redux-form';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow'; import flow from 'lodash/flow';
import { renderRadioField, toNumber } from '../../../helpers/form'; import { renderRadioField, toNumber } from '../../../helpers/form';
import { STATS_INTERVALS_DAYS } from '../../../helpers/constants'; import { STATS_INTERVALS_DAYS } from '../../../helpers/constants';
const getIntervalFields = (processing, t, toNumber) => const getIntervalFields = (processing, t, toNumber) => STATS_INTERVALS_DAYS.map((interval) => {
STATS_INTERVALS_DAYS.map((interval) => { const title = interval === 1 ? t('interval_24_hour') : t('interval_days', { count: interval });
const title =
interval === 1 ? t('interval_24_hour') : t('interval_days', { count: interval });
return ( return (
<Field <Field
key={interval} key={interval}
name="interval" name="interval"
@ -23,8 +21,8 @@ const getIntervalFields = (processing, t, toNumber) =>
normalize={toNumber} normalize={toNumber}
disabled={processing} disabled={processing}
/> />
); );
}); });
const Form = (props) => { const Form = (props) => {
const { const {
@ -77,7 +75,7 @@ Form.propTypes = {
}; };
export default flow([ export default flow([
withNamespaces(), withTranslation(),
reduxForm({ reduxForm({
form: 'statsConfigForm', form: 'statsConfigForm',
}), }),

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import Card from '../../ui/Card'; import Card from '../../ui/Card';
import Form from './Form'; import Form from './Form';
@ -52,4 +52,4 @@ StatsConfig.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(StatsConfig); export default withTranslation()(StatsConfig);

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import Services from './Services'; import Services from './Services';
import StatsConfig from './StatsConfig'; import StatsConfig from './StatsConfig';
@ -76,11 +76,10 @@ class Settings extends Component {
t, t,
} = this.props; } = this.props;
const isDataReady = const isDataReady = !settings.processing
!settings.processing && && !services.processing
!services.processing && && !stats.processingGetConfig
!stats.processingGetConfig && && !queryLogs.processingGetConfig;
!queryLogs.processingGetConfig;
return ( return (
<Fragment> <Fragment>
@ -146,6 +145,33 @@ Settings.propTypes = {
setFiltersConfig: PropTypes.func.isRequired, setFiltersConfig: PropTypes.func.isRequired,
getFilteringStatus: PropTypes.func.isRequired, getFilteringStatus: PropTypes.func.isRequired,
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
getBlockedServices: PropTypes.func,
getLogsConfig: PropTypes.func,
setBlockedServices: PropTypes.func,
setLogsConfig: PropTypes.func,
clearLogs: PropTypes.func,
services: PropTypes.shape({
processing: PropTypes.bool,
}),
stats: PropTypes.shape({
processingGetConfig: PropTypes.bool,
interval: PropTypes.number,
processingSetConfig: PropTypes.bool,
processingReset: PropTypes.bool,
}),
queryLogs: PropTypes.shape({
enabled: PropTypes.bool,
interval: PropTypes.number,
anonymize_client_ip: PropTypes.bool,
processingSetConfig: PropTypes.bool,
processingClear: PropTypes.bool,
processingGetConfig: PropTypes.bool,
}),
filtering: PropTypes.shape({
interval: PropTypes.number,
enabled: PropTypes.bool,
processingSetConfig: PropTypes.bool,
}),
}; };
export default withNamespaces()(Settings); export default withTranslation()(Settings);

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import Guide from '../ui/Guide'; import Guide from '../ui/Guide';
import Card from '../ui/Card'; import Card from '../ui/Card';
@ -25,7 +25,7 @@ const SetupGuide = ({
<Trans>install_devices_address</Trans>: <Trans>install_devices_address</Trans>:
</div> </div>
<div className="mt-2 font-weight-bold"> <div className="mt-2 font-weight-bold">
{dnsAddresses.map(ip => <li key={ip}>{ip}</li>)} {dnsAddresses.map((ip) => <li key={ip}>{ip}</li>)}
</div> </div>
</div> </div>
<Guide dnsAddresses={dnsAddresses} /> <Guide dnsAddresses={dnsAddresses} />
@ -38,4 +38,4 @@ SetupGuide.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(SetupGuide); export default withTranslation()(SetupGuide);

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
class Toast extends Component { class Toast extends Component {
componentDidMount() { componentDidMount() {
@ -49,4 +49,4 @@ Toast.propTypes = {
removeToast: PropTypes.func.isRequired, removeToast: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Toast); export default withTranslation()(Toast);

View File

@ -7,21 +7,21 @@ import Toast from './Toast';
import './Toast.css'; import './Toast.css';
const Toasts = props => ( const Toasts = (props) => (
<TransitionGroup className="toasts"> <TransitionGroup className="toasts">
{props.toasts.notices && props.toasts.notices.map((toast) => { {props.toasts.notices && props.toasts.notices.map((toast) => {
const { id } = toast; const { id } = toast;
return ( return (
<CSSTransition <CSSTransition
key={id} key={id}
timeout={500} timeout={500}
classNames="toast" classNames="toast"
> >
<Toast removeToast={props.removeToast} {...toast} /> <Toast removeToast={props.removeToast} {...toast} />
</CSSTransition> </CSSTransition>
); );
})} })}
</TransitionGroup> </TransitionGroup>
); );
Toasts.propTypes = { Toasts.propTypes = {
@ -39,4 +39,3 @@ export default connect(
mapStateToProps, mapStateToProps,
actionCreators, actionCreators,
)(Toasts); )(Toasts);

View File

@ -6,10 +6,10 @@ import './Accordion.css';
class Accordion extends Component { class Accordion extends Component {
state = { state = {
isOpen: false, isOpen: false,
} };
handleClick = () => { handleClick = () => {
this.setState(prevState => ({ isOpen: !prevState.isOpen })); this.setState((prevState) => ({ isOpen: !prevState.isOpen }));
}; };
render() { render() {

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import './Checkbox.css'; import './Checkbox.css';
@ -38,4 +38,4 @@ Checkbox.propTypes = {
t: PropTypes.func, t: PropTypes.func,
}; };
export default withNamespaces()(Checkbox); export default withTranslation()(Checkbox);

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import { withNamespaces } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import enhanceWithClickOutside from 'react-click-outside'; import enhanceWithClickOutside from 'react-click-outside';
import './Dropdown.css'; import './Dropdown.css';
@ -12,7 +12,7 @@ class Dropdown extends Component {
}; };
toggleDropdown = () => { toggleDropdown = () => {
this.setState(prevState => ({ isOpen: !prevState.isOpen })); this.setState((prevState) => ({ isOpen: !prevState.isOpen }));
}; };
hideDropdown = () => { hideDropdown = () => {
@ -86,4 +86,4 @@ Dropdown.propTypes = {
icon: PropTypes.string, icon: PropTypes.string,
}; };
export default withNamespaces()(enhanceWithClickOutside(Dropdown)); export default withTranslation()(enhanceWithClickOutside(Dropdown));

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import isAfter from 'date-fns/is_after'; import isAfter from 'date-fns/is_after';
import addDays from 'date-fns/add_days'; import addDays from 'date-fns/add_days';
@ -23,7 +23,7 @@ const EncryptionTopline = (props) => {
</Trans> </Trans>
</Topline> </Topline>
); );
} else if (isAboutExpire) { } if (isAboutExpire) {
return ( return (
<Topline type="warning"> <Topline type="warning">
<Trans components={[<a href="#encryption" key="0">link</a>]}> <Trans components={[<a href="#encryption" key="0">link</a>]}>
@ -40,4 +40,4 @@ EncryptionTopline.propTypes = {
notAfter: PropTypes.string.isRequired, notAfter: PropTypes.string.isRequired,
}; };
export default withNamespaces()(EncryptionTopline); export default withTranslation()(EncryptionTopline);

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import { REPOSITORY, PRIVACY_POLICY_LINK } from '../../helpers/constants'; import { REPOSITORY, PRIVACY_POLICY_LINK } from '../../helpers/constants';
import { LANGUAGES } from '../../helpers/twosky'; import { LANGUAGES } from '../../helpers/twosky';
@ -70,7 +70,7 @@ class Footer extends Component {
value={i18n.language} value={i18n.language}
onChange={this.changeLanguage} onChange={this.changeLanguage}
> >
{Object.keys(LANGUAGES).map(lang => ( {Object.keys(LANGUAGES).map((lang) => (
<option key={lang} value={lang}> <option key={lang} value={lang}>
{LANGUAGES[lang]} {LANGUAGES[lang]}
</option> </option>
@ -112,4 +112,4 @@ Footer.propTypes = {
getVersion: PropTypes.func, getVersion: PropTypes.func,
}; };
export default withNamespaces()(Footer); export default withTranslation()(Footer);

View File

@ -1,15 +1,14 @@
import React, { Fragment } 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, withTranslation } from 'react-i18next';
import Tabs from '../ui/Tabs'; import Tabs from './Tabs';
import Icons from '../ui/Icons'; import Icons from './Icons';
const Guide = (props) => { const Guide = (props) => {
const { dnsAddresses } = props; const { dnsAddresses } = props;
const tlsAddress = (dnsAddresses && dnsAddresses.filter(item => item.includes('tls://'))) || ''; const tlsAddress = (dnsAddresses && dnsAddresses.filter((item) => item.includes('tls://'))) || '';
const httpsAddress = const httpsAddress = (dnsAddresses && dnsAddresses.filter((item) => item.includes('https://'))) || '';
(dnsAddresses && dnsAddresses.filter(item => item.includes('https://'))) || '';
const showDnsPrivacyNotice = httpsAddress.length < 1 && tlsAddress.length < 1; const showDnsPrivacyNotice = httpsAddress.length < 1 && tlsAddress.length < 1;
return ( return (
@ -373,4 +372,4 @@ Guide.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Guide); export default withTranslation()(Guide);

View File

@ -4,51 +4,49 @@ import { ResponsiveLine } from '@nivo/line';
import './Line.css'; import './Line.css';
const Line = ({ data, color }) => ( const Line = ({ data, color }) => data
data && && <ResponsiveLine
<ResponsiveLine data={data}
data={data} margin={{
margin={{ top: 15,
top: 15, right: 0,
right: 0, bottom: 1,
bottom: 1, left: 20,
left: 20, }}
}} minY="auto"
minY="auto" stacked={false}
stacked={false} curve='linear'
curve='linear' axisBottom={null}
axisBottom={null} axisLeft={null}
axisLeft={null} enableGridX={false}
enableGridX={false} enableGridY={false}
enableGridY={false} enableDots={false}
enableDots={false} enableArea={true}
enableArea={true} animate={false}
animate={false} colorBy={() => (color)}
colorBy={() => (color)} tooltip={(slice) => (
tooltip={slice => ( <div>
<div> {slice.data.map((d) => (
{slice.data.map(d => ( <div key={d.serie.id} className="line__tooltip">
<div key={d.serie.id} className="line__tooltip">
<span className="line__tooltip-text"> <span className="line__tooltip-text">
<strong>{d.data.y}</strong> <strong>{d.data.y}</strong>
<br/> <br />
<small>{d.data.x}</small> <small>{d.data.x}</small>
</span> </span>
</div> </div>
))} ))}
</div> </div>
)} )}
theme={{ theme={{
tooltip: { tooltip: {
container: { container: {
padding: '0', padding: '0',
background: '#333', background: '#333',
borderRadius: '4px', borderRadius: '4px',
},
}, },
}} },
/> }}
); />;
Line.propTypes = { Line.propTypes = {
data: PropTypes.array.isRequired, data: PropTypes.array.isRequired,

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import './PageTitle.css'; import './PageTitle.css';
const PageTitle = props => ( const PageTitle = (props) => (
<div className="page-header"> <div className="page-header">
<h1 className="page-title"> <h1 className="page-title">
{props.title} {props.title}

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import { getSourceData } from '../../helpers/trackers/trackers'; import { getSourceData } from '../../helpers/trackers/trackers';
import { captitalizeWords } from '../../helpers/helpers'; import { captitalizeWords } from '../../helpers/helpers';
@ -53,4 +53,4 @@ Popover.propTypes = {
data: PropTypes.object.isRequired, data: PropTypes.object.isRequired,
}; };
export default withNamespaces()(Popover); export default withTranslation()(Popover);

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import './Popover.css'; import './Popover.css';
@ -49,4 +49,4 @@ PopoverFilter.propTypes = {
service: PropTypes.string, service: PropTypes.string,
}; };
export default withNamespaces()(PopoverFilter); export default withTranslation()(PopoverFilter);

View File

@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withNamespaces, Trans } from 'react-i18next'; import { withTranslation, Trans } from 'react-i18next';
import Card from '../ui/Card'; import Card from './Card';
const Status = ({ message, buttonMessage, reloadPage }) => ( const Status = ({ message, buttonMessage, reloadPage }) => (
<div className="status"> <div className="status">
@ -10,8 +10,8 @@ const Status = ({ message, buttonMessage, reloadPage }) => (
<div className="h4 font-weight-light mb-4"> <div className="h4 font-weight-light mb-4">
<Trans>{message}</Trans> <Trans>{message}</Trans>
</div> </div>
{buttonMessage && {buttonMessage
<button className="btn btn-success" onClick={reloadPage}> && <button className="btn btn-success" onClick={reloadPage}>
<Trans>{buttonMessage}</Trans> <Trans>{buttonMessage}</Trans>
</button>} </button>}
</Card> </Card>
@ -24,4 +24,4 @@ Status.propTypes = {
reloadPage: PropTypes.func, reloadPage: PropTypes.func,
}; };
export default withNamespaces()(Status); export default withTranslation()(Status);

View File

@ -187,7 +187,7 @@ a {
color: #467fcf; color: #467fcf;
text-decoration: none; text-decoration: none;
background-color: transparent; background-color: transparent;
-webkit-text-decoration-skip: objects; -webkittext-decoration-skip-ink: objects
} }
a:hover { a:hover {
@ -9863,8 +9863,8 @@ body *:hover::-webkit-scrollbar-thumb {
} }
a { a {
-webkit-text-decoration-skip: ink; -webkit-text-decoration-skip: auto;
text-decoration-skip: ink; text-decoration-skip-ink: auto
} }
h1 a, h1 a,

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import './Tooltip.css'; import './Tooltip.css';
const Tooltip = props => ( const Tooltip = (props) => (
<div data-tooltip={props.text} className={`tooltip-custom ${props.type || ''}`}></div> <div data-tooltip={props.text} className={`tooltip-custom ${props.type || ''}`}></div>
); );

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import './Topline.css'; import './Topline.css';
const Topline = props => ( const Topline = (props) => (
<div className={`alert alert-${props.type} topline`}> <div className={`alert alert-${props.type} topline`}>
<div className="container"> <div className="container">
{props.children} {props.children}

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import classnames from 'classnames'; import classnames from 'classnames';
import './Overlay.css'; import './Overlay.css';
@ -23,4 +23,4 @@ UpdateOverlay.propTypes = {
processingUpdate: PropTypes.bool, processingUpdate: PropTypes.bool,
}; };
export default withNamespaces()(UpdateOverlay); export default withTranslation()(UpdateOverlay);

View File

@ -1,10 +1,10 @@
import React, { Fragment } 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, withTranslation } from 'react-i18next';
import Topline from './Topline'; import Topline from './Topline';
const UpdateTopline = props => ( const UpdateTopline = (props) => (
<Topline type="info"> <Topline type="info">
<Fragment> <Fragment>
<Trans <Trans
@ -17,8 +17,8 @@ const UpdateTopline = props => (
> >
update_announcement update_announcement
</Trans> </Trans>
{props.canAutoUpdate && {props.canAutoUpdate
<button && <button
type="button" type="button"
className="btn btn-sm btn-primary ml-3" className="btn btn-sm btn-primary ml-3"
onClick={props.getUpdate} onClick={props.getUpdate}
@ -39,4 +39,4 @@ UpdateTopline.propTypes = {
processingUpdate: PropTypes.bool, processingUpdate: PropTypes.bool,
}; };
export default withNamespaces()(UpdateTopline); export default withTranslation()(UpdateTopline);

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next'; import { Trans, withTranslation } from 'react-i18next';
import './Version.css'; import './Version.css';
@ -36,4 +36,4 @@ Version.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
}; };
export default withNamespaces()(Version); export default withTranslation()(Version);

View File

@ -9,7 +9,7 @@ export default function configureStore(reducer, initialState) {
/* eslint-disable no-underscore-dangle */ /* eslint-disable no-underscore-dangle */
const store = createStore(reducer, initialState, compose( const store = createStore(reducer, initialState, compose(
applyMiddleware(...middlewares), applyMiddleware(...middlewares),
window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f, window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : (f) => f,
)); ));
/* eslint-enable */ /* eslint-enable */
return store; return store;

View File

@ -1,7 +1,9 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { getClients } from '../actions'; import { getClients } from '../actions';
import { getStats } from '../actions/stats'; import { getStats } from '../actions/stats';
import { addClient, updateClient, deleteClient, toggleClientModal } from '../actions/clients'; import {
addClient, updateClient, deleteClient, toggleClientModal,
} from '../actions/clients';
import Clients from '../components/Settings/Clients'; import Clients from '../components/Settings/Clients';
const mapStateToProps = (state) => { const mapStateToProps = (state) => {

Some files were not shown because too many files have changed in this diff Show More