diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 99fcefc4..2ddf108f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -44,4 +44,4 @@ jobs: fields: repo,message,commit,author env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} \ No newline at end of file + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/client/babel.config.js b/client/babel.config.js index c6fdd790..3a56c36e 100644 --- a/client/babel.config.js +++ b/client/babel.config.js @@ -11,6 +11,7 @@ module.exports = (api) => { '@babel/plugin-proposal-object-rest-spread', '@babel/plugin-proposal-nullish-coalescing-operator', '@babel/plugin-proposal-optional-chaining', + 'react-hot-loader/babel', ], }; }; diff --git a/client/constants.js b/client/constants.js new file mode 100644 index 00000000..c7c9a0e1 --- /dev/null +++ b/client/constants.js @@ -0,0 +1,11 @@ +const BUILD_ENVS = { + dev: 'development', + prod: 'production', +}; + +const BASE_URL = '/control'; + +module.exports = { + BUILD_ENVS, + BASE_URL, +}; diff --git a/client/package-lock.json b/client/package-lock.json index 62884d65..bff06737 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1356,6 +1356,17 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" }, + "@hot-loader/react-dom": { + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/@hot-loader/react-dom/-/react-dom-16.13.0.tgz", + "integrity": "sha512-lJZrmkucz2MrQJTQtJobx5MICXcfQvKihszqv655p557HPi0hMOWxrNpiHv3DWD8ugNWjtWcVWqRnFvwsHq1mQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.0" + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2257,6 +2268,12 @@ "@types/istanbul-lib-report": "*" } }, + "@types/json-schema": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", + "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -2728,7 +2745,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -5108,6 +5124,12 @@ } } }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -5201,9 +5223,9 @@ "dev": true }, "elliptic": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", - "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", "dev": true, "requires": { "bn.js": "^4.4.0", @@ -5216,9 +5238,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", "dev": true } } @@ -5887,8 +5909,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { "version": "1.3.1", @@ -6844,6 +6865,16 @@ } } }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, "global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -7357,18 +7388,6 @@ "requires-port": "^1.0.0" } }, - "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", - "dev": true, - "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - } - }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -9898,10 +9917,9 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -10628,6 +10646,15 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "dev": true, + "requires": { + "dom-walk": "^0.1.0" + } + }, "min-indent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz", @@ -12287,6 +12314,39 @@ "scheduler": "^0.19.1" } }, + "react-hot-loader": { + "version": "4.12.21", + "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.12.21.tgz", + "integrity": "sha512-Ynxa6ROfWUeKWsTHxsrL2KMzujxJVPjs385lmB2t5cHUxdoRPGind9F00tOkdc1l5WBleOF4XEAMILY1KPIIDA==", + "dev": true, + "requires": { + "fast-levenshtein": "^2.0.6", + "global": "^4.3.0", + "hoist-non-react-statics": "^3.3.0", + "loader-utils": "^1.1.0", + "prop-types": "^15.6.1", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, + "requires": { + "react-is": "^16.7.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, "react-i18next": { "version": "11.4.0", "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.4.0.tgz", @@ -13328,6 +13388,12 @@ "safe-buffer": "^5.0.1" } }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -13491,7 +13557,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -13751,8 +13818,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { "version": "1.16.1", @@ -14079,12 +14145,13 @@ } }, "schema-utils": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz", - "integrity": "sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", "dev": true, "requires": { - "ajv": "^6.12.0", + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", "ajv-keywords": "^3.4.1" } } @@ -15930,6 +15997,18 @@ "ms": "^2.1.1" } }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/client/package.json b/client/package.json index 1fd8c465..41690780 100644 --- a/client/package.json +++ b/client/package.json @@ -4,14 +4,16 @@ "private": true, "scripts": { "build-dev": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js", - "watch": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js --watch", "build-prod": "cross-env BUILD_ENV=prod webpack --config webpack.prod.js", + "watch": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js --watch", + "watch:hot": "cross-env BUILD_ENV=dev webpack-dev-server --config webpack.dev.js", "lint": "eslint src", "lint:fix": "eslint src --fix", "test": "jest", "test:watch": "jest --watch" }, "dependencies": { + "@hot-loader/react-dom": "^16.13.0", "@nivo/line": "^0.49.1", "axios": "^0.19.2", "classnames": "^2.2.6", @@ -19,6 +21,7 @@ "i18next": "^19.4.4", "i18next-browser-languagedetector": "^4.2.0", "ipaddr.js": "^1.9.1", + "js-yaml": "^3.14.0", "lodash": "^4.17.19", "nanoid": "^3.1.9", "prop-types": "^15.7.2", @@ -73,6 +76,7 @@ "path": "^0.12.7", "postcss-flexbugs-fixes": "4.2.1", "postcss-loader": "^3.0.0", + "react-hot-loader": "^4.12.21", "style-loader": "^1.2.1", "stylelint": "^13.5.0", "stylelint-webpack-plugin": "2.0.0", diff --git a/client/src/actions/index.js b/client/src/actions/index.js index a8245d73..29338e35 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -148,7 +148,7 @@ const checkStatus = async (handleRequestSuccess, handleRequestError, attempts = const rmTimeout = (t) => t && clearTimeout(t); try { - const response = await axios.get('control/status'); + const response = await axios.get(`${apiClient.baseUrl}/status`); rmTimeout(timeout); if (response?.status === 200) { handleRequestSuccess(response); diff --git a/client/src/api/Api.js b/client/src/api/Api.js index 74090d1a..e309e3bd 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -2,9 +2,10 @@ import axios from 'axios'; import { getPathWithQueryString } from '../helpers/helpers'; import { R_PATH_LAST_PART } from '../helpers/constants'; +import { BASE_URL } from '../../constants'; class Api { - baseUrl = 'control'; + baseUrl = BASE_URL; async makeRequest(path, method = 'POST', config) { try { @@ -26,18 +27,30 @@ class Api { throw new Error(`${errorPath} | ${error.response.data} | ${error.response.status}`); } - throw new Error(`${errorPath} | ${error.message ? error.message : error}`); + throw new Error(`${errorPath} | ${error.message || error}`); } } // 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() { const { path, method } = this.GLOBAL_STATUS; @@ -68,21 +81,45 @@ class Api { } // 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() { const { path, method } = this.FILTERING_STATUS; @@ -153,11 +190,20 @@ class Api { } // 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() { const { path, method } = this.PARENTAL_STATUS; @@ -180,11 +226,20 @@ class Api { } // 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() { const { path, method } = this.SAFEBROWSING_STATUS; @@ -202,11 +257,20 @@ class Api { } // 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() { const { path, method } = this.SAFESEARCH_STATUS; @@ -224,9 +288,15 @@ class Api { } // 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() { const { path, method } = this.CURRENT_LANGUAGE; @@ -243,19 +313,40 @@ class Api { } // 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() { const { path, method } = this.DHCP_STATUS; @@ -309,11 +400,20 @@ class Api { } // 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() { const { path, method } = this.INSTALL_GET_ADDRESSES; @@ -339,11 +439,20 @@ class Api { } // 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() { const { path, method } = this.TLS_STATUS; @@ -369,15 +478,30 @@ class Api { } // 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() { const { path, method } = this.GET_CLIENTS; @@ -418,9 +542,15 @@ class Api { } // 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() { const { path, method } = this.ACCESS_LIST; @@ -437,11 +567,20 @@ class Api { } // 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() { const { path, method } = this.REWRITES_LIST; @@ -467,9 +606,15 @@ class Api { } // 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() { const { path, method } = this.BLOCKED_SERVICES_LIST; @@ -486,13 +631,25 @@ class Api { } // 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() { const { path, method } = this.GET_STATS; @@ -519,13 +676,25 @@ class Api { } // 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) { const { path, method } = this.GET_QUERY_LOG; @@ -553,7 +722,10 @@ class Api { } // Login - LOGIN = { path: 'login', method: 'POST' }; + LOGIN = { + path: 'login', + method: 'POST', + }; login(data) { const { path, method } = this.LOGIN; @@ -565,7 +737,10 @@ class Api { } // Profile - GET_PROFILE = { path: 'profile', method: 'GET' }; + GET_PROFILE = { + path: 'profile', + method: 'GET', + }; getProfile() { const { path, method } = this.GET_PROFILE; @@ -573,9 +748,15 @@ class Api { } // 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() { const { path, method } = this.GET_DNS_CONFIG; diff --git a/client/src/components/App/index.js b/client/src/components/App/index.js index 71b33039..8ccd30ef 100644 --- a/client/src/components/App/index.js +++ b/client/src/components/App/index.js @@ -1,30 +1,16 @@ -import React, { Component, Fragment } from 'react'; +import React, { useEffect } from 'react'; import { HashRouter, Route } from 'react-router-dom'; -import PropTypes from 'prop-types'; -import { withTranslation } from 'react-i18next'; import LoadingBar from 'react-redux-loading-bar'; +import { hot } from 'react-hot-loader/root'; import 'react-table/react-table.css'; import '../ui/Tabler.css'; import '../ui/ReactTable.css'; import './index.css'; -import Header from '../../containers/Header'; -import Dashboard from '../../containers/Dashboard'; -import Settings from '../../containers/Settings'; +import { shallowEqual, useDispatch, useSelector } from 'react-redux'; -import CustomRules from '../../containers/CustomRules'; -import DnsBlocklist from '../../containers/DnsBlocklist'; -import DnsAllowlist from '../../containers/DnsAllowlist'; -import DnsRewrites from '../../containers/DnsRewrites'; - -import Dns from '../../containers/Dns'; -import Encryption from '../../containers/Encryption'; -import Dhcp from '../../containers/Dhcp'; -import Clients from '../../containers/Clients'; - -import Logs from '../../containers/Logs'; -import SetupGuide from '../../containers/SetupGuide'; +import propTypes from 'prop-types'; import Toasts from '../Toasts'; import Footer from '../ui/Footer'; import Status from '../ui/Status'; @@ -35,31 +21,107 @@ import Icons from '../ui/Icons'; import i18n from '../../i18n'; import Loading from '../ui/Loading'; import { FILTERS_URLS, MENU_URLS, SETTINGS_URLS } from '../../helpers/constants'; -import Services from '../Filters/Services'; import { getLogsUrlParams, setHtmlLangAttr } from '../../helpers/helpers'; +import Header from '../Header'; +import { changeLanguage, getDnsStatus } from '../../actions'; -class App extends Component { - componentDidMount() { - this.props.getDnsStatus(); - } +import Dashboard from '../../containers/Dashboard'; +import Logs from '../../containers/Logs'; +import SetupGuide from '../../containers/SetupGuide'; +import Settings from '../../containers/Settings'; +import Dns from '../../containers/Dns'; +import Encryption from '../../containers/Encryption'; +import Dhcp from '../../containers/Dhcp'; +import Clients from '../../containers/Clients'; +import DnsBlocklist from '../../containers/DnsBlocklist'; +import DnsAllowlist from '../../containers/DnsAllowlist'; +import DnsRewrites from '../../containers/DnsRewrites'; +import CustomRules from '../../containers/CustomRules'; +import Services from '../Filters/Services'; - componentDidUpdate(prevProps) { - if (this.props.dashboard.language !== prevProps.dashboard.language) { - this.setLanguage(); - } - } +const ROUTES = [ + { + path: MENU_URLS.root, + component: Dashboard, + exact: true, + }, + { + path: [`${MENU_URLS.logs}${getLogsUrlParams(':search?', ':response_status?')}`, MENU_URLS.logs], + component: Logs, + }, + { + path: MENU_URLS.guide, + component: SetupGuide, + }, + { + path: SETTINGS_URLS.settings, + component: Settings, + }, + { + path: SETTINGS_URLS.dns, + component: Dns, + }, + { + path: SETTINGS_URLS.encryption, + component: Encryption, + }, + { + path: SETTINGS_URLS.dhcp, + component: Dhcp, + }, + { + path: SETTINGS_URLS.clients, + component: Clients, + }, + { + path: FILTERS_URLS.dns_blocklists, + component: DnsBlocklist, + }, + { + path: FILTERS_URLS.dns_allowlists, + component: DnsAllowlist, + }, + { + path: FILTERS_URLS.dns_rewrites, + component: DnsRewrites, + }, + { + path: FILTERS_URLS.custom_rules, + component: CustomRules, + }, + { + path: FILTERS_URLS.blocked_services, + component: Services, + }, +]; - reloadPage = () => { - window.location.reload(); - }; +const renderRoute = ({ path, component, exact }, idx) => ; - handleUpdate = () => { - this.props.getUpdate(); - }; +const App = () => { + const dispatch = useDispatch(); + const { + language, + isCoreRunning, + isUpdateAvailable, + processing, + } = useSelector((state) => state.dashboard, shallowEqual); - setLanguage = () => { - const { processing, language } = this.props.dashboard; + const { processing: processingEncryption } = useSelector(( + state, + ) => state.encryption, shallowEqual); + const updateAvailable = isCoreRunning && isUpdateAvailable; + + useEffect(() => { + dispatch(getDnsStatus()); + }, []); + + const setLanguage = () => { if (!processing) { if (language) { i18n.changeLanguage(language); @@ -68,93 +130,52 @@ class App extends Component { } i18n.on('languageChanged', (lang) => { - this.props.changeLanguage(lang); + dispatch(changeLanguage(lang)); }); }; - render() { - const { dashboard, encryption, getVersion } = this.props; - const updateAvailable = dashboard.isCoreRunning && dashboard.isUpdateAvailable; + useEffect(() => { + setLanguage(); + }, [language]); - return ( - - - {updateAvailable && ( - - - - - )} - {!encryption.processing && ( - - )} - - -
- {dashboard.processing && } - {!dashboard.isCoreRunning && ( -
-
- - -
+ const reloadPage = () => { + window.location.reload(); + }; + + return ( + + <> + {updateAvailable && <> + + + } + {!processingEncryption && } + +
+
+ {processing && } + {!isCoreRunning && ( +
+
+ +
- )} - {!dashboard.processing && dashboard.isCoreRunning && ( - <> - - - - - - - - - - - - - - - )} -
-
- - - - - ); - } -} - -App.propTypes = { - getDnsStatus: PropTypes.func, - getUpdate: PropTypes.func, - enableDns: PropTypes.func, - dashboard: PropTypes.object, - isCoreRunning: PropTypes.bool, - error: PropTypes.string, - changeLanguage: PropTypes.func, - encryption: PropTypes.object, - getVersion: PropTypes.func, +
+ )} + {!processing && isCoreRunning && ROUTES.map(renderRoute)} +
+