mirror of
				https://github.com/optim-enterprises-bv/OptimCloud-gw-ui.git
				synced 2025-10-31 18:27:45 +00:00 
			
		
		
		
	Initial push
This commit is contained in:
		
							
								
								
									
										450
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										450
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1152,6 +1152,76 @@ | |||||||
|         "minimist": "^1.2.0" |         "minimist": "^1.2.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "@coreui/chartjs": { | ||||||
|  |       "version": "2.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@coreui/chartjs/-/chartjs-2.0.0.tgz", | ||||||
|  |       "integrity": "sha512-degpSo1MqSWomkNwuXk2VQijEENqkaufEGI/i6/3ClVQNZQIWB5NG6QWA/aCTXt9Y/3tVfnuTzDC4YHw7E+Brg==", | ||||||
|  |       "requires": { | ||||||
|  |         "@coreui/coreui": "^3.0.0-beta.1", | ||||||
|  |         "chart.js": "^2.8.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "@coreui/coreui": { | ||||||
|  |       "version": "3.4.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@coreui/coreui/-/coreui-3.4.0.tgz", | ||||||
|  |       "integrity": "sha512-WqzockdWVkXUNmNwlqdu+AxM+9JoiWGe4rKaySu/dZme1NvVOn2ukjJlpTkssal8UKcSHyitzNixtkMCmUxE1A==" | ||||||
|  |     }, | ||||||
|  |     "@coreui/icons": { | ||||||
|  |       "version": "2.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@coreui/icons/-/icons-2.0.1.tgz", | ||||||
|  |       "integrity": "sha512-gBfFRLPUt3Bv9EZbJRbT3sQRHrhH0c4dRbeE9GpWJgJY8kvE9+3Hf5xGK9XyQhFynHx4o2WQeMxsReQLddlK9w==" | ||||||
|  |     }, | ||||||
|  |     "@coreui/icons-react": { | ||||||
|  |       "version": "1.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@coreui/icons-react/-/icons-react-1.1.0.tgz", | ||||||
|  |       "integrity": "sha512-OXDg09RsxlK5t6WizudsJUxgzJSAHeytwVG1hqn2ww5zIrJn5++5rNTp95N/kff4/er4f7jspwJ1/7n6mQAz2Q==", | ||||||
|  |       "requires": { | ||||||
|  |         "classnames": "^2.2.6", | ||||||
|  |         "prop-types": "^15.7.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "@coreui/react": { | ||||||
|  |       "version": "3.4.6", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@coreui/react/-/react-3.4.6.tgz", | ||||||
|  |       "integrity": "sha512-qu9/2kDNb24jXMaoGolOM5Jp9+wdweVWPJFixnAOMCobhUt0TNHa9yJakCfr7mopMV8teYvWBjBhl5I2er1/xw==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.13.10", | ||||||
|  |         "@coreui/icons": "^2.0.0-rc.0", | ||||||
|  |         "@coreui/icons-react": "^1.1.0", | ||||||
|  |         "@coreui/utils": "~1.3.1", | ||||||
|  |         "@popperjs/core": "^2.9.1", | ||||||
|  |         "classnames": "~2.2.6", | ||||||
|  |         "core-js": "^3.9.1", | ||||||
|  |         "perfect-scrollbar": "~1.5.0", | ||||||
|  |         "prop-types": "~15.7.2", | ||||||
|  |         "react-transition-group": "~4.4.1", | ||||||
|  |         "tippy.js": "^6.3.1" | ||||||
|  |       }, | ||||||
|  |       "dependencies": { | ||||||
|  |         "classnames": { | ||||||
|  |           "version": "2.2.6", | ||||||
|  |           "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", | ||||||
|  |           "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "@coreui/react-chartjs": { | ||||||
|  |       "version": "1.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@coreui/react-chartjs/-/react-chartjs-1.1.0.tgz", | ||||||
|  |       "integrity": "sha512-xa925PmaBeh+2x+AY/macovW7KOe4W+VaxNcLKndY10GFSsEjryCrY7s9QXiIUqoQJQMXMeiXMbSoTuhIJ/aEA==", | ||||||
|  |       "requires": { | ||||||
|  |         "@coreui/chartjs": "^2.0.0", | ||||||
|  |         "@types/chart.js": "^2.9.31", | ||||||
|  |         "chart.js": "^2.9.4", | ||||||
|  |         "classnames": "^2.2.6", | ||||||
|  |         "prop-types": "^15.7.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "@coreui/utils": { | ||||||
|  |       "version": "1.3.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@coreui/utils/-/utils-1.3.1.tgz", | ||||||
|  |       "integrity": "sha512-WuWHX7bg89cJH34TWVsLe9RsxzBhTApj+X2Ja19xhjcpxt5Gv11Ozm+fwYt6DD7DgncTvpwYrMcnNlpp701UOg==" | ||||||
|  |     }, | ||||||
|     "@csstools/convert-colors": { |     "@csstools/convert-colors": { | ||||||
|       "version": "1.4.0", |       "version": "1.4.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", |       "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", | ||||||
| @@ -1193,6 +1263,35 @@ | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "@fortawesome/fontawesome-common-types": { | ||||||
|  |       "version": "0.2.35", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz", | ||||||
|  |       "integrity": "sha512-IHUfxSEDS9dDGqYwIW7wTN6tn/O8E0n5PcAHz9cAaBoZw6UpG20IG/YM3NNLaGPwPqgjBAFjIURzqoQs3rrtuw==" | ||||||
|  |     }, | ||||||
|  |     "@fortawesome/fontawesome-svg-core": { | ||||||
|  |       "version": "1.2.35", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.35.tgz", | ||||||
|  |       "integrity": "sha512-uLEXifXIL7hnh2sNZQrIJWNol7cTVIzwI+4qcBIq9QWaZqUblm0IDrtSqbNg+3SQf8SMGHkiSigD++rHmCHjBg==", | ||||||
|  |       "requires": { | ||||||
|  |         "@fortawesome/fontawesome-common-types": "^0.2.35" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "@fortawesome/free-solid-svg-icons": { | ||||||
|  |       "version": "5.15.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.3.tgz", | ||||||
|  |       "integrity": "sha512-XPeeu1IlGYqz4VWGRAT5ukNMd4VHUEEJ7ysZ7pSSgaEtNvSo+FLurybGJVmiqkQdK50OkSja2bfZXOeyMGRD8Q==", | ||||||
|  |       "requires": { | ||||||
|  |         "@fortawesome/fontawesome-common-types": "^0.2.35" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "@fortawesome/react-fontawesome": { | ||||||
|  |       "version": "0.1.14", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.14.tgz", | ||||||
|  |       "integrity": "sha512-4wqNb0gRLVaBm/h+lGe8UfPPivcbuJ6ecI4hIgW0LjI7kzpYB9FkN0L9apbVzg+lsBdcTf0AlBtODjcSX5mmKA==", | ||||||
|  |       "requires": { | ||||||
|  |         "prop-types": "^15.7.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "@hapi/address": { |     "@hapi/address": { | ||||||
|       "version": "2.1.4", |       "version": "2.1.4", | ||||||
|       "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", |       "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", | ||||||
| @@ -1824,15 +1923,23 @@ | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "@reduxjs/toolkit": { |     "@popperjs/core": { | ||||||
|       "version": "1.5.1", |       "version": "2.9.2", | ||||||
|       "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.5.1.tgz", |       "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz", | ||||||
|       "integrity": "sha512-PngZKuwVZsd+mimnmhiOQzoD0FiMjqVks6ituO1//Ft5UEX5Ca9of13NEjo//pU22Jk7z/mdXVsmDfgsig1osA==", |       "integrity": "sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==" | ||||||
|  |     }, | ||||||
|  |     "@restart/context": { | ||||||
|  |       "version": "2.1.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz", | ||||||
|  |       "integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q==" | ||||||
|  |     }, | ||||||
|  |     "@restart/hooks": { | ||||||
|  |       "version": "0.3.26", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.26.tgz", | ||||||
|  |       "integrity": "sha512-7Hwk2ZMYm+JLWcb7R9qIXk1OoUg1Z+saKWqZXlrvFwT3w6UArVNWgxYOzf+PJoK9zZejp8okPAKTctthhXLt5g==", | ||||||
|       "requires": { |       "requires": { | ||||||
|         "immer": "^8.0.1", |         "lodash": "^4.17.20", | ||||||
|         "redux": "^4.0.0", |         "lodash-es": "^4.17.20" | ||||||
|         "redux-thunk": "^2.3.0", |  | ||||||
|         "reselect": "^4.0.0" |  | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "@rollup/plugin-node-resolve": { |     "@rollup/plugin-node-resolve": { | ||||||
| @@ -2252,6 +2359,19 @@ | |||||||
|         "@babel/types": "^7.3.0" |         "@babel/types": "^7.3.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "@types/chart.js": { | ||||||
|  |       "version": "2.9.32", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.32.tgz", | ||||||
|  |       "integrity": "sha512-d45JiRQwEOlZiKwukjqmqpbqbYzUX2yrXdH9qVn6kXpPDsTYCo6YbfFOlnUaJ8S/DhJwbBJiLsMjKpW5oP8B2A==", | ||||||
|  |       "requires": { | ||||||
|  |         "moment": "^2.10.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "@types/classnames": { | ||||||
|  |       "version": "2.2.11", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.11.tgz", | ||||||
|  |       "integrity": "sha512-2koNhpWm3DgWRp5tpkiJ8JGc1xTn2q0l+jUNUE7oMKXUf5NpI9AIdC4kbjGNFBdHtcxBD18LAksoudAVhFKCjw==" | ||||||
|  |     }, | ||||||
|     "@types/eslint": { |     "@types/eslint": { | ||||||
|       "version": "7.2.8", |       "version": "7.2.8", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.8.tgz", |       "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.8.tgz", | ||||||
| @@ -2297,6 +2417,11 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", |       "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", | ||||||
|       "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==" |       "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==" | ||||||
|     }, |     }, | ||||||
|  |     "@types/invariant": { | ||||||
|  |       "version": "2.2.34", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.34.tgz", | ||||||
|  |       "integrity": "sha512-lYUtmJ9BqUN688fGY1U1HZoWT1/Jrmgigx2loq4ZcJpICECm/Om3V314BxdzypO0u5PORKGMM6x0OXaljV1YFg==" | ||||||
|  |     }, | ||||||
|     "@types/istanbul-lib-coverage": { |     "@types/istanbul-lib-coverage": { | ||||||
|       "version": "2.0.3", |       "version": "2.0.3", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", |       "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", | ||||||
| @@ -2392,6 +2517,14 @@ | |||||||
|         "redux": "^4.0.0" |         "redux": "^4.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "@types/react-transition-group": { | ||||||
|  |       "version": "4.4.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", | ||||||
|  |       "integrity": "sha512-vIo69qKKcYoJ8wKCJjwSgCTM+z3chw3g18dkrDfVX665tMH7tmbDxEAnPdey4gTlwZz5QuHGzd+hul0OVZDqqQ==", | ||||||
|  |       "requires": { | ||||||
|  |         "@types/react": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "@types/resolve": { |     "@types/resolve": { | ||||||
|       "version": "0.0.8", |       "version": "0.0.8", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", |       "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", | ||||||
| @@ -2574,6 +2707,11 @@ | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "@types/warning": { | ||||||
|  |       "version": "3.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", | ||||||
|  |       "integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=" | ||||||
|  |     }, | ||||||
|     "@types/webpack": { |     "@types/webpack": { | ||||||
|       "version": "4.41.27", |       "version": "4.41.27", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.27.tgz", |       "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.27.tgz", | ||||||
| @@ -3238,6 +3376,22 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.4.tgz", |       "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.4.tgz", | ||||||
|       "integrity": "sha512-Pdgfv6iP0gNx9ejRGa3zE7Xgkj/iclXqLfe7BnatdZz0QnLZ3jrRHUVH8wNSdN68w05Sk3ShGTb3ydktMTooig==" |       "integrity": "sha512-Pdgfv6iP0gNx9ejRGa3zE7Xgkj/iclXqLfe7BnatdZz0QnLZ3jrRHUVH8wNSdN68w05Sk3ShGTb3ydktMTooig==" | ||||||
|     }, |     }, | ||||||
|  |     "axios": { | ||||||
|  |       "version": "0.21.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", | ||||||
|  |       "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", | ||||||
|  |       "requires": { | ||||||
|  |         "follow-redirects": "^1.10.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "axios-retry": { | ||||||
|  |       "version": "3.1.9", | ||||||
|  |       "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.1.9.tgz", | ||||||
|  |       "integrity": "sha512-NFCoNIHq8lYkJa6ku4m+V1837TP6lCa7n79Iuf8/AqATAHYB0ISaAS1eyIenDOfHOLtym34W65Sjke2xjg2fsA==", | ||||||
|  |       "requires": { | ||||||
|  |         "is-retry-allowed": "^1.1.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "axobject-query": { |     "axobject-query": { | ||||||
|       "version": "2.2.0", |       "version": "2.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", |       "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", | ||||||
| @@ -3791,8 +3945,7 @@ | |||||||
|     "binary-extensions": { |     "binary-extensions": { | ||||||
|       "version": "2.2.0", |       "version": "2.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", |       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", | ||||||
|       "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", |       "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" | ||||||
|       "optional": true |  | ||||||
|     }, |     }, | ||||||
|     "bindings": { |     "bindings": { | ||||||
|       "version": "1.5.0", |       "version": "1.5.0", | ||||||
| @@ -3873,6 +4026,11 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", |       "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", | ||||||
|       "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" |       "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" | ||||||
|     }, |     }, | ||||||
|  |     "bootstrap": { | ||||||
|  |       "version": "4.6.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz", | ||||||
|  |       "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==" | ||||||
|  |     }, | ||||||
|     "brace-expansion": { |     "brace-expansion": { | ||||||
|       "version": "1.1.11", |       "version": "1.1.11", | ||||||
|       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", |       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", | ||||||
| @@ -4188,6 +4346,32 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", |       "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", | ||||||
|       "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==" |       "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==" | ||||||
|     }, |     }, | ||||||
|  |     "chart.js": { | ||||||
|  |       "version": "2.9.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", | ||||||
|  |       "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", | ||||||
|  |       "requires": { | ||||||
|  |         "chartjs-color": "^2.1.0", | ||||||
|  |         "moment": "^2.10.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "chartjs-color": { | ||||||
|  |       "version": "2.4.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", | ||||||
|  |       "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", | ||||||
|  |       "requires": { | ||||||
|  |         "chartjs-color-string": "^0.6.0", | ||||||
|  |         "color-convert": "^1.9.3" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "chartjs-color-string": { | ||||||
|  |       "version": "0.6.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", | ||||||
|  |       "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", | ||||||
|  |       "requires": { | ||||||
|  |         "color-name": "^1.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "check-types": { |     "check-types": { | ||||||
|       "version": "11.1.2", |       "version": "11.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", |       "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", | ||||||
| @@ -4197,7 +4381,6 @@ | |||||||
|       "version": "3.5.1", |       "version": "3.5.1", | ||||||
|       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", |       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", | ||||||
|       "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", |       "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", | ||||||
|       "optional": true, |  | ||||||
|       "requires": { |       "requires": { | ||||||
|         "anymatch": "~3.1.1", |         "anymatch": "~3.1.1", | ||||||
|         "braces": "~3.0.2", |         "braces": "~3.0.2", | ||||||
| @@ -4259,6 +4442,11 @@ | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "classnames": { | ||||||
|  |       "version": "2.3.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", | ||||||
|  |       "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" | ||||||
|  |     }, | ||||||
|     "clean-css": { |     "clean-css": { | ||||||
|       "version": "4.2.3", |       "version": "4.2.3", | ||||||
|       "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", |       "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", | ||||||
| @@ -5312,6 +5500,15 @@ | |||||||
|         "utila": "~0.4" |         "utila": "~0.4" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "dom-helpers": { | ||||||
|  |       "version": "5.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", | ||||||
|  |       "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.8.7", | ||||||
|  |         "csstype": "^3.0.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "dom-serializer": { |     "dom-serializer": { | ||||||
|       "version": "0.2.2", |       "version": "0.2.2", | ||||||
|       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", |       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", | ||||||
| @@ -7328,6 +7525,19 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", |       "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", | ||||||
|       "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" |       "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" | ||||||
|     }, |     }, | ||||||
|  |     "history": { | ||||||
|  |       "version": "4.10.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", | ||||||
|  |       "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.1.2", | ||||||
|  |         "loose-envify": "^1.2.0", | ||||||
|  |         "resolve-pathname": "^3.0.0", | ||||||
|  |         "tiny-invariant": "^1.0.2", | ||||||
|  |         "tiny-warning": "^1.0.0", | ||||||
|  |         "value-equal": "^1.0.1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "hmac-drbg": { |     "hmac-drbg": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", | ||||||
| @@ -7818,6 +8028,14 @@ | |||||||
|         "side-channel": "^1.0.4" |         "side-channel": "^1.0.4" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "invariant": { | ||||||
|  |       "version": "2.2.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", | ||||||
|  |       "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", | ||||||
|  |       "requires": { | ||||||
|  |         "loose-envify": "^1.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "ip": { |     "ip": { | ||||||
|       "version": "1.1.5", |       "version": "1.1.5", | ||||||
|       "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", |       "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", | ||||||
| @@ -7878,7 +8096,6 @@ | |||||||
|       "version": "2.1.0", |       "version": "2.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", |       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", | ||||||
|       "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", |       "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", | ||||||
|       "optional": true, |  | ||||||
|       "requires": { |       "requires": { | ||||||
|         "binary-extensions": "^2.0.0" |         "binary-extensions": "^2.0.0" | ||||||
|       } |       } | ||||||
| @@ -8091,6 +8308,11 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", |       "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", | ||||||
|       "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" |       "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" | ||||||
|     }, |     }, | ||||||
|  |     "is-retry-allowed": { | ||||||
|  |       "version": "1.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", | ||||||
|  |       "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" | ||||||
|  |     }, | ||||||
|     "is-root": { |     "is-root": { | ||||||
|       "version": "2.1.0", |       "version": "2.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", |       "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", | ||||||
| @@ -9944,6 +10166,11 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", |       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", | ||||||
|       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" |       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" | ||||||
|     }, |     }, | ||||||
|  |     "lodash-es": { | ||||||
|  |       "version": "4.17.21", | ||||||
|  |       "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", | ||||||
|  |       "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" | ||||||
|  |     }, | ||||||
|     "lodash._reinterpolate": { |     "lodash._reinterpolate": { | ||||||
|       "version": "3.0.0", |       "version": "3.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", |       "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", | ||||||
| @@ -10208,6 +10435,15 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", | ||||||
|       "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" |       "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" | ||||||
|     }, |     }, | ||||||
|  |     "mini-create-react-context": { | ||||||
|  |       "version": "0.4.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", | ||||||
|  |       "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.12.1", | ||||||
|  |         "tiny-warning": "^1.0.3" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "mini-css-extract-plugin": { |     "mini-css-extract-plugin": { | ||||||
|       "version": "0.11.3", |       "version": "0.11.3", | ||||||
|       "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz", |       "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz", | ||||||
| @@ -10357,6 +10593,11 @@ | |||||||
|         "minimist": "^1.2.5" |         "minimist": "^1.2.5" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "moment": { | ||||||
|  |       "version": "2.29.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", | ||||||
|  |       "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" | ||||||
|  |     }, | ||||||
|     "move-concurrently": { |     "move-concurrently": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", | ||||||
| @@ -11089,6 +11330,11 @@ | |||||||
|         "sha.js": "^2.4.8" |         "sha.js": "^2.4.8" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "perfect-scrollbar": { | ||||||
|  |       "version": "1.5.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.0.tgz", | ||||||
|  |       "integrity": "sha512-NrNHJn5mUGupSiheBTy6x+6SXCFbLlm8fVZh9moIzw/LgqElN5q4ncR4pbCBCYuCJ8Kcl9mYM0NgDxvW+b4LxA==" | ||||||
|  |     }, | ||||||
|     "performance-now": { |     "performance-now": { | ||||||
|       "version": "2.1.0", |       "version": "2.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", |       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", | ||||||
| @@ -12344,6 +12590,15 @@ | |||||||
|         "react-is": "^16.8.1" |         "react-is": "^16.8.1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "prop-types-extra": { | ||||||
|  |       "version": "1.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", | ||||||
|  |       "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", | ||||||
|  |       "requires": { | ||||||
|  |         "react-is": "^16.3.2", | ||||||
|  |         "warning": "^4.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "proxy-addr": { |     "proxy-addr": { | ||||||
|       "version": "2.0.6", |       "version": "2.0.6", | ||||||
|       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", |       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", | ||||||
| @@ -12527,6 +12782,31 @@ | |||||||
|         "whatwg-fetch": "^3.4.1" |         "whatwg-fetch": "^3.4.1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "react-bootstrap": { | ||||||
|  |       "version": "1.5.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.5.2.tgz", | ||||||
|  |       "integrity": "sha512-mGKPY5+lLd7Vtkx2VFivoRkPT4xAHazuFfIhJLTEgHlDfIUSePn7qrmpZe5gXH9zvHV0RsBaQ9cLfXjxnZrOpA==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.13.8", | ||||||
|  |         "@restart/context": "^2.1.4", | ||||||
|  |         "@restart/hooks": "^0.3.26", | ||||||
|  |         "@types/classnames": "^2.2.10", | ||||||
|  |         "@types/invariant": "^2.2.33", | ||||||
|  |         "@types/prop-types": "^15.7.3", | ||||||
|  |         "@types/react": ">=16.9.35", | ||||||
|  |         "@types/react-transition-group": "^4.4.1", | ||||||
|  |         "@types/warning": "^3.0.0", | ||||||
|  |         "classnames": "^2.2.6", | ||||||
|  |         "dom-helpers": "^5.1.2", | ||||||
|  |         "invariant": "^2.2.4", | ||||||
|  |         "prop-types": "^15.7.2", | ||||||
|  |         "prop-types-extra": "^1.1.0", | ||||||
|  |         "react-overlays": "^5.0.0", | ||||||
|  |         "react-transition-group": "^4.4.1", | ||||||
|  |         "uncontrollable": "^7.2.1", | ||||||
|  |         "warning": "^4.0.3" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "react-dev-utils": { |     "react-dev-utils": { | ||||||
|       "version": "11.0.4", |       "version": "11.0.4", | ||||||
|       "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", |       "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", | ||||||
| @@ -12653,6 +12933,26 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", |       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", | ||||||
|       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" |       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" | ||||||
|     }, |     }, | ||||||
|  |     "react-lifecycles-compat": { | ||||||
|  |       "version": "3.0.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", | ||||||
|  |       "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" | ||||||
|  |     }, | ||||||
|  |     "react-overlays": { | ||||||
|  |       "version": "5.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.0.0.tgz", | ||||||
|  |       "integrity": "sha512-TKbqfAv23TFtCJ2lzISdx76p97G/DP8Rp4TOFdqM9n8GTruVYgE3jX7Zgb8+w7YJ18slTVcDTQ1/tFzdCqjVhA==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.12.1", | ||||||
|  |         "@popperjs/core": "^2.5.3", | ||||||
|  |         "@restart/hooks": "^0.3.25", | ||||||
|  |         "@types/warning": "^3.0.0", | ||||||
|  |         "dom-helpers": "^5.2.0", | ||||||
|  |         "prop-types": "^15.7.2", | ||||||
|  |         "uncontrollable": "^7.0.0", | ||||||
|  |         "warning": "^4.0.3" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "react-redux": { |     "react-redux": { | ||||||
|       "version": "7.2.3", |       "version": "7.2.3", | ||||||
|       "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.3.tgz", |       "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.3.tgz", | ||||||
| @@ -12671,6 +12971,52 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", |       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", | ||||||
|       "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" |       "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" | ||||||
|     }, |     }, | ||||||
|  |     "react-router": { | ||||||
|  |       "version": "5.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", | ||||||
|  |       "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.1.2", | ||||||
|  |         "history": "^4.9.0", | ||||||
|  |         "hoist-non-react-statics": "^3.1.0", | ||||||
|  |         "loose-envify": "^1.3.1", | ||||||
|  |         "mini-create-react-context": "^0.4.0", | ||||||
|  |         "path-to-regexp": "^1.7.0", | ||||||
|  |         "prop-types": "^15.6.2", | ||||||
|  |         "react-is": "^16.6.0", | ||||||
|  |         "tiny-invariant": "^1.0.2", | ||||||
|  |         "tiny-warning": "^1.0.0" | ||||||
|  |       }, | ||||||
|  |       "dependencies": { | ||||||
|  |         "isarray": { | ||||||
|  |           "version": "0.0.1", | ||||||
|  |           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", | ||||||
|  |           "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" | ||||||
|  |         }, | ||||||
|  |         "path-to-regexp": { | ||||||
|  |           "version": "1.8.0", | ||||||
|  |           "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", | ||||||
|  |           "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", | ||||||
|  |           "requires": { | ||||||
|  |             "isarray": "0.0.1" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "react-router-dom": { | ||||||
|  |       "version": "5.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", | ||||||
|  |       "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.1.2", | ||||||
|  |         "history": "^4.9.0", | ||||||
|  |         "loose-envify": "^1.3.1", | ||||||
|  |         "prop-types": "^15.6.2", | ||||||
|  |         "react-router": "5.2.0", | ||||||
|  |         "tiny-invariant": "^1.0.2", | ||||||
|  |         "tiny-warning": "^1.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "react-scripts": { |     "react-scripts": { | ||||||
|       "version": "4.0.3", |       "version": "4.0.3", | ||||||
|       "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.3.tgz", |       "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.3.tgz", | ||||||
| @@ -12737,6 +13083,17 @@ | |||||||
|         "workbox-webpack-plugin": "5.1.4" |         "workbox-webpack-plugin": "5.1.4" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "react-transition-group": { | ||||||
|  |       "version": "4.4.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", | ||||||
|  |       "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.5.5", | ||||||
|  |         "dom-helpers": "^5.0.1", | ||||||
|  |         "loose-envify": "^1.4.0", | ||||||
|  |         "prop-types": "^15.6.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "read-pkg": { |     "read-pkg": { | ||||||
|       "version": "2.0.0", |       "version": "2.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", |       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", | ||||||
| @@ -12830,7 +13187,6 @@ | |||||||
|       "version": "3.5.0", |       "version": "3.5.0", | ||||||
|       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", |       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", | ||||||
|       "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", |       "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", | ||||||
|       "optional": true, |  | ||||||
|       "requires": { |       "requires": { | ||||||
|         "picomatch": "^2.2.1" |         "picomatch": "^2.2.1" | ||||||
|       } |       } | ||||||
| @@ -12861,11 +13217,6 @@ | |||||||
|         "symbol-observable": "^1.2.0" |         "symbol-observable": "^1.2.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "redux-thunk": { |  | ||||||
|       "version": "2.3.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", |  | ||||||
|       "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" |  | ||||||
|     }, |  | ||||||
|     "regenerate": { |     "regenerate": { | ||||||
|       "version": "1.4.2", |       "version": "1.4.2", | ||||||
|       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", |       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", | ||||||
| @@ -13092,11 +13443,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", |       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", | ||||||
|       "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" |       "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" | ||||||
|     }, |     }, | ||||||
|     "reselect": { |  | ||||||
|       "version": "4.0.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", |  | ||||||
|       "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" |  | ||||||
|     }, |  | ||||||
|     "resolve": { |     "resolve": { | ||||||
|       "version": "1.18.1", |       "version": "1.18.1", | ||||||
|       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", |       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", | ||||||
| @@ -13126,6 +13472,11 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", |       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", | ||||||
|       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" |       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" | ||||||
|     }, |     }, | ||||||
|  |     "resolve-pathname": { | ||||||
|  |       "version": "3.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", | ||||||
|  |       "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" | ||||||
|  |     }, | ||||||
|     "resolve-url": { |     "resolve-url": { | ||||||
|       "version": "0.2.1", |       "version": "0.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", |       "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", | ||||||
| @@ -13511,6 +13862,14 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz", |       "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz", | ||||||
|       "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg==" |       "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg==" | ||||||
|     }, |     }, | ||||||
|  |     "sass": { | ||||||
|  |       "version": "1.32.8", | ||||||
|  |       "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.8.tgz", | ||||||
|  |       "integrity": "sha512-Sl6mIeGpzjIUZqvKnKETfMf0iDAswD9TNlv13A7aAF3XZlRPMq4VvJWBC2N2DXbp94MQVdNSFG6LfF/iOXrPHQ==", | ||||||
|  |       "requires": { | ||||||
|  |         "chokidar": ">=2.0.0 <4.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "sass-loader": { |     "sass-loader": { | ||||||
|       "version": "10.1.1", |       "version": "10.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.1.1.tgz", |       "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.1.1.tgz", | ||||||
| @@ -14784,6 +15143,24 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", |       "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", | ||||||
|       "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" |       "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" | ||||||
|     }, |     }, | ||||||
|  |     "tiny-invariant": { | ||||||
|  |       "version": "1.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", | ||||||
|  |       "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" | ||||||
|  |     }, | ||||||
|  |     "tiny-warning": { | ||||||
|  |       "version": "1.0.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", | ||||||
|  |       "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" | ||||||
|  |     }, | ||||||
|  |     "tippy.js": { | ||||||
|  |       "version": "6.3.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.1.tgz", | ||||||
|  |       "integrity": "sha512-JnFncCq+rF1dTURupoJ4yPie5Cof978inW6/4S6kmWV7LL9YOSEVMifED3KdrVPEG+Z/TFH2CDNJcQEfaeuQww==", | ||||||
|  |       "requires": { | ||||||
|  |         "@popperjs/core": "^2.8.3" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "tmpl": { |     "tmpl": { | ||||||
|       "version": "1.0.4", |       "version": "1.0.4", | ||||||
|       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", |       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", | ||||||
| @@ -14984,6 +15361,17 @@ | |||||||
|         "which-boxed-primitive": "^1.0.2" |         "which-boxed-primitive": "^1.0.2" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "uncontrollable": { | ||||||
|  |       "version": "7.2.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", | ||||||
|  |       "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", | ||||||
|  |       "requires": { | ||||||
|  |         "@babel/runtime": "^7.6.3", | ||||||
|  |         "@types/react": ">=16.9.11", | ||||||
|  |         "invariant": "^2.2.4", | ||||||
|  |         "react-lifecycles-compat": "^3.0.4" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "unicode-canonical-property-names-ecmascript": { |     "unicode-canonical-property-names-ecmascript": { | ||||||
|       "version": "1.0.4", |       "version": "1.0.4", | ||||||
|       "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", |       "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", | ||||||
| @@ -15223,8 +15611,7 @@ | |||||||
|     "uuid": { |     "uuid": { | ||||||
|       "version": "8.3.2", |       "version": "8.3.2", | ||||||
|       "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", |       "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", | ||||||
|       "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", |       "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" | ||||||
|       "optional": true |  | ||||||
|     }, |     }, | ||||||
|     "v8-compile-cache": { |     "v8-compile-cache": { | ||||||
|       "version": "2.3.0", |       "version": "2.3.0", | ||||||
| @@ -15257,6 +15644,11 @@ | |||||||
|         "spdx-expression-parse": "^3.0.0" |         "spdx-expression-parse": "^3.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "value-equal": { | ||||||
|  |       "version": "1.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", | ||||||
|  |       "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" | ||||||
|  |     }, | ||||||
|     "vary": { |     "vary": { | ||||||
|       "version": "1.1.2", |       "version": "1.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", |       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", | ||||||
| @@ -15311,6 +15703,14 @@ | |||||||
|         "makeerror": "1.0.x" |         "makeerror": "1.0.x" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "warning": { | ||||||
|  |       "version": "4.0.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", | ||||||
|  |       "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", | ||||||
|  |       "requires": { | ||||||
|  |         "loose-envify": "^1.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "watchpack": { |     "watchpack": { | ||||||
|       "version": "1.7.5", |       "version": "1.7.5", | ||||||
|       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", |       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								package.json
									
									
									
									
									
								
							| @@ -3,14 +3,30 @@ | |||||||
|   "version": "0.1.0", |   "version": "0.1.0", | ||||||
|   "private": true, |   "private": true, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@reduxjs/toolkit": "^1.5.1", |     "@coreui/chartjs": "^2.0.0", | ||||||
|  |     "@coreui/coreui": "^3.4.0", | ||||||
|  |     "@coreui/icons": "^2.0.1", | ||||||
|  |     "@coreui/icons-react": "^1.1.0", | ||||||
|  |     "@coreui/react": "^3.4.6", | ||||||
|  |     "@coreui/react-chartjs": "^1.1.0", | ||||||
|  |     "@coreui/utils": "^1.3.1", | ||||||
|  |     "@fortawesome/fontawesome-svg-core": "^1.2.35", | ||||||
|  |     "@fortawesome/free-solid-svg-icons": "^5.15.3", | ||||||
|  |     "@fortawesome/react-fontawesome": "^0.1.14", | ||||||
|     "@testing-library/jest-dom": "^4.2.4", |     "@testing-library/jest-dom": "^4.2.4", | ||||||
|     "@testing-library/react": "^9.5.0", |     "@testing-library/react": "^9.5.0", | ||||||
|     "@testing-library/user-event": "^7.2.1", |     "@testing-library/user-event": "^7.2.1", | ||||||
|  |     "axios": "^0.21.1", | ||||||
|  |     "axios-retry": "^3.1.9", | ||||||
|  |     "bootstrap": "^4.6.0", | ||||||
|     "react": "^17.0.2", |     "react": "^17.0.2", | ||||||
|  |     "react-bootstrap": "^1.5.2", | ||||||
|     "react-dom": "^17.0.2", |     "react-dom": "^17.0.2", | ||||||
|     "react-redux": "^7.2.3", |     "react-redux": "^7.2.3", | ||||||
|     "react-scripts": "4.0.3" |     "react-router-dom": "^5.2.0", | ||||||
|  |     "react-scripts": "4.0.3", | ||||||
|  |     "sass": "^1.32.8", | ||||||
|  |     "uuid": "^8.3.2" | ||||||
|   }, |   }, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "start": "react-scripts start", |     "start": "react-scripts start", | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ | |||||||
|       work correctly both with client-side routing and a non-root public URL. |       work correctly both with client-side routing and a non-root public URL. | ||||||
|       Learn how to configure a non-root public URL by running `npm run build`. |       Learn how to configure a non-root public URL by running `npm run build`. | ||||||
|     --> |     --> | ||||||
|     <title>React Redux App</title> |     <title> UcentralGW</title> | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
|     <noscript>You need to enable JavaScript to run this app.</noscript> |     <noscript>You need to enable JavaScript to run this app.</noscript> | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								src/App.css
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								src/App.css
									
									
									
									
									
								
							| @@ -1,39 +0,0 @@ | |||||||
| .App { |  | ||||||
|   text-align: center; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .App-logo { |  | ||||||
|   height: 40vmin; |  | ||||||
|   pointer-events: none; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @media (prefers-reduced-motion: no-preference) { |  | ||||||
|   .App-logo { |  | ||||||
|     animation: App-logo-float infinite 3s ease-in-out; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .App-header { |  | ||||||
|   min-height: 100vh; |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: column; |  | ||||||
|   align-items: center; |  | ||||||
|   justify-content: center; |  | ||||||
|   font-size: calc(10px + 2vmin); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .App-link { |  | ||||||
|   color: rgb(112, 76, 182); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @keyframes App-logo-float { |  | ||||||
|   0% { |  | ||||||
|     transform: translateY(0); |  | ||||||
|   } |  | ||||||
|   50% { |  | ||||||
|     transform: translateY(10px); |  | ||||||
|   } |  | ||||||
|   100% { |  | ||||||
|     transform: translateY(0px); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										89
									
								
								src/App.js
									
									
									
									
									
								
							
							
						
						
									
										89
									
								
								src/App.js
									
									
									
									
									
								
							| @@ -1,58 +1,41 @@ | |||||||
| import React from 'react'; | import React, { useEffect } from 'react'; | ||||||
| import logo from './logo.svg'; | import { HashRouter, Route, Switch } from 'react-router-dom'; | ||||||
| import { Counter } from './features/counter/Counter'; | import './scss/style.scss'; | ||||||
| import './App.css'; | import { useSelector, useDispatch } from 'react-redux'; | ||||||
|  |  | ||||||
| function App() { | const loading = ( | ||||||
|   return ( |   <div className="pt-3 text-center"> | ||||||
|     <div className="App"> |     <div className="sk-spinner sk-spinner-pulse"></div> | ||||||
|       <header className="App-header"> |  | ||||||
|         <img src={logo} className="App-logo" alt="logo" /> |  | ||||||
|         <Counter /> |  | ||||||
|         <p> |  | ||||||
|           Edit <code>src/App.js</code> and save to reload. |  | ||||||
|         </p> |  | ||||||
|         <span> |  | ||||||
|           <span>Learn </span> |  | ||||||
|           <a |  | ||||||
|             className="App-link" |  | ||||||
|             href="https://reactjs.org/" |  | ||||||
|             target="_blank" |  | ||||||
|             rel="noopener noreferrer" |  | ||||||
|           > |  | ||||||
|             React |  | ||||||
|           </a> |  | ||||||
|           <span>, </span> |  | ||||||
|           <a |  | ||||||
|             className="App-link" |  | ||||||
|             href="https://redux.js.org/" |  | ||||||
|             target="_blank" |  | ||||||
|             rel="noopener noreferrer" |  | ||||||
|           > |  | ||||||
|             Redux |  | ||||||
|           </a> |  | ||||||
|           <span>, </span> |  | ||||||
|           <a |  | ||||||
|             className="App-link" |  | ||||||
|             href="https://redux-toolkit.js.org/" |  | ||||||
|             target="_blank" |  | ||||||
|             rel="noopener noreferrer" |  | ||||||
|           > |  | ||||||
|             Redux Toolkit |  | ||||||
|           </a> |  | ||||||
|           ,<span> and </span> |  | ||||||
|           <a |  | ||||||
|             className="App-link" |  | ||||||
|             href="https://react-redux.js.org/" |  | ||||||
|             target="_blank" |  | ||||||
|             rel="noopener noreferrer" |  | ||||||
|           > |  | ||||||
|             React Redux |  | ||||||
|           </a> |  | ||||||
|         </span> |  | ||||||
|       </header> |  | ||||||
|   </div> |   </div> | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const TheLayout = React.lazy(() => import('./containers/TheLayout')); | ||||||
|  | const Login = React.lazy(() => import('./views/pages/Login')); | ||||||
|  | const Page404 = React.lazy(() => import('./views/pages/Page404')); | ||||||
|  | const Page500 = React.lazy(() => import('./views/pages/Page500')); | ||||||
|  |  | ||||||
|  | const App = () => { | ||||||
|  |     const isLoggedIn  = useSelector(state => state.connected); | ||||||
|  |     const dispatch = useDispatch(); | ||||||
|  |  | ||||||
|  |     useEffect(() => { | ||||||
|  |         const token = sessionStorage.getItem('access_token'); | ||||||
|  |         if (token !== undefined && token !== null) { | ||||||
|  |             dispatch({type: 'set', connected: true}); | ||||||
|  |         } | ||||||
|  |     }, [dispatch]); | ||||||
|  |  | ||||||
|  |     return ( | ||||||
|  |         <HashRouter> | ||||||
|  |                 <React.Suspense fallback={loading}> | ||||||
|  |                 <Switch> | ||||||
|  |                     <Route exact path="/404" name="Page 404" render={props => <Page404 {...props}/>} /> | ||||||
|  |                     <Route exact path="/500" name="Page 500" render={props => <Page500 {...props}/>} /> | ||||||
|  |                     <Route path="/" name="Devices" render={props => isLoggedIn ?  <TheLayout {...props}/> : <Login {...props}/>} /> | ||||||
|  |                 </Switch> | ||||||
|  |                 </React.Suspense> | ||||||
|  |             </HashRouter> | ||||||
|     ); |     ); | ||||||
| } | }; | ||||||
|  |  | ||||||
| export default App; | export default App; | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| import { configureStore } from '@reduxjs/toolkit'; |  | ||||||
| import counterReducer from '../features/counter/counterSlice'; |  | ||||||
|  |  | ||||||
| export const store = configureStore({ |  | ||||||
|   reducer: { |  | ||||||
|     counter: counterReducer, |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
							
								
								
									
										262
									
								
								src/assets/icons/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								src/assets/icons/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | |||||||
|  | import { sygnet } from './sygnet' | ||||||
|  | import { logo } from './logo' | ||||||
|  | import { logoNegative } from './logo-negative' | ||||||
|  |  | ||||||
|  | import { | ||||||
|  |   cibSkype, | ||||||
|  |   cibFacebook, | ||||||
|  |   cibTwitter, | ||||||
|  |   cibLinkedin, | ||||||
|  |   cibFlickr, | ||||||
|  |   cibTumblr, | ||||||
|  |   cibXing, | ||||||
|  |   cibGithub, | ||||||
|  |   cibStackoverflow, | ||||||
|  |   cibYoutube, | ||||||
|  |   cibDribbble, | ||||||
|  |   cibInstagram, | ||||||
|  |   cibPinterest, | ||||||
|  |   cibVk, | ||||||
|  |   cibYahoo, | ||||||
|  |   cibBehance, | ||||||
|  |   cibReddit, | ||||||
|  |   cibVimeo, | ||||||
|  |   cibCcMastercard, | ||||||
|  |   cibCcVisa, | ||||||
|  |   cibStripe, | ||||||
|  |   cibPaypal, | ||||||
|  |   cibGooglePay, | ||||||
|  |   cibCcAmex | ||||||
|  | } from '@coreui/icons' | ||||||
|  | import { | ||||||
|  |   cifUs, | ||||||
|  |   cifBr, | ||||||
|  |   cifIn, | ||||||
|  |   cifFr, | ||||||
|  |   cifEs, | ||||||
|  |   cifPl | ||||||
|  | } from '@coreui/icons' | ||||||
|  | import { | ||||||
|  |   cilAlignCenter, | ||||||
|  |   cilAlignLeft, | ||||||
|  |   cilAlignRight, | ||||||
|  |   cilApplicationsSettings, | ||||||
|  |   cilArrowRight, | ||||||
|  |   cilArrowTop, | ||||||
|  |   cilAsterisk, | ||||||
|  |   cilBan, | ||||||
|  |   cilBasket, | ||||||
|  |   cilBell, | ||||||
|  |   cilBold, | ||||||
|  |   cilBookmark, | ||||||
|  |   cilCalculator, | ||||||
|  |   cilCalendar, | ||||||
|  |   cilCloudDownload, | ||||||
|  |   cilChartPie, | ||||||
|  |   cilCheck, | ||||||
|  |   cilChevronBottom, | ||||||
|  |   cilChevronLeft, | ||||||
|  |   cilChevronRight, | ||||||
|  |   cilChevronTop, | ||||||
|  |   cilCircle, | ||||||
|  |   cilCheckCircle, | ||||||
|  |   cilCode, | ||||||
|  |   cilCommentSquare, | ||||||
|  |   cilCreditCard, | ||||||
|  |   cilCursor, | ||||||
|  |   cilCursorMove, | ||||||
|  |   cilDrop, | ||||||
|  |   cilDollar, | ||||||
|  |   cilEnvelopeClosed, | ||||||
|  |   cilEnvelopeLetter, | ||||||
|  |   cilEnvelopeOpen, | ||||||
|  |   cilEuro, | ||||||
|  |   cilGlobeAlt, | ||||||
|  |   cilGrid, | ||||||
|  |   cilFile, | ||||||
|  |   cilFullscreen, | ||||||
|  |   cilFullscreenExit, | ||||||
|  |   cilGraph, | ||||||
|  |   cilHome, | ||||||
|  |   cilInbox, | ||||||
|  |   cilIndentDecrease, | ||||||
|  |   cilIndentIncrease, | ||||||
|  |   cilInputPower, | ||||||
|  |   cilItalic, | ||||||
|  |   cilJustifyCenter, | ||||||
|  |   cilJustifyLeft, | ||||||
|  |   cilLaptop, | ||||||
|  |   cilLayers, | ||||||
|  |   cilLightbulb, | ||||||
|  |   cilList, | ||||||
|  |   cilListNumbered, | ||||||
|  |   cilListRich, | ||||||
|  |   cilLocationPin, | ||||||
|  |   cilLockLocked, | ||||||
|  |   cilMagnifyingGlass, | ||||||
|  |   cilMap, | ||||||
|  |   cilMoon, | ||||||
|  |   cilNotes, | ||||||
|  |   cilOptions, | ||||||
|  |   cilPaperclip, | ||||||
|  |   cilPaperPlane, | ||||||
|  |   cilPencil, | ||||||
|  |   cilPeople, | ||||||
|  |   cilPhone, | ||||||
|  |   cilPrint, | ||||||
|  |   cilPuzzle, | ||||||
|  |   cilSave, | ||||||
|  |   cilScrubber, | ||||||
|  |   cilSettings, | ||||||
|  |   cilShare, | ||||||
|  |   cilShareAll, | ||||||
|  |   cilShareBoxed, | ||||||
|  |   cilShieldAlt, | ||||||
|  |   cilSpeech, | ||||||
|  |   cilSpeedometer, | ||||||
|  |   cilSpreadsheet, | ||||||
|  |   cilStar, | ||||||
|  |   cilSun, | ||||||
|  |   cilTags, | ||||||
|  |   cilTask, | ||||||
|  |   cilTrash, | ||||||
|  |   cilUnderline, | ||||||
|  |   cilUser, | ||||||
|  |   cilUserFemale, | ||||||
|  |   cilUserFollow, | ||||||
|  |   cilUserUnfollow, | ||||||
|  |   cilX, | ||||||
|  |   cilXCircle, | ||||||
|  |   cilWarning | ||||||
|  | } from '@coreui/icons' | ||||||
|  |  | ||||||
|  | export const icons = Object.assign({}, { | ||||||
|  |   sygnet, | ||||||
|  |   logo, | ||||||
|  |   logoNegative | ||||||
|  | }, { | ||||||
|  |   cilAlignCenter, | ||||||
|  |   cilAlignLeft, | ||||||
|  |   cilAlignRight, | ||||||
|  |   cilApplicationsSettings, | ||||||
|  |   cilArrowRight, | ||||||
|  |   cilArrowTop, | ||||||
|  |   cilAsterisk, | ||||||
|  |   cilBan, | ||||||
|  |   cilBasket, | ||||||
|  |   cilBell, | ||||||
|  |   cilBold, | ||||||
|  |   cilBookmark, | ||||||
|  |   cilCalculator, | ||||||
|  |   cilCalendar, | ||||||
|  |   cilCloudDownload, | ||||||
|  |  | ||||||
|  |   cilChartPie, | ||||||
|  |   cilCheck, | ||||||
|  |   cilChevronBottom, | ||||||
|  |   cilChevronLeft, | ||||||
|  |   cilChevronRight, | ||||||
|  |   cilChevronTop, | ||||||
|  |   cilCircle, | ||||||
|  |   cilCheckCircle, | ||||||
|  |   cilCode, | ||||||
|  |   cilCommentSquare, | ||||||
|  |   cilCreditCard, | ||||||
|  |   cilCursor, | ||||||
|  |   cilCursorMove, | ||||||
|  |   cilDrop, | ||||||
|  |   cilDollar, | ||||||
|  |   cilEnvelopeClosed, | ||||||
|  |   cilEnvelopeLetter, | ||||||
|  |   cilEnvelopeOpen, | ||||||
|  |   cilEuro, | ||||||
|  |   cilGlobeAlt, | ||||||
|  |   cilGrid, | ||||||
|  |   cilFile, | ||||||
|  |   cilFullscreen, | ||||||
|  |   cilFullscreenExit, | ||||||
|  |   cilGraph, | ||||||
|  |   cilHome, | ||||||
|  |   cilInbox, | ||||||
|  |   cilIndentDecrease, | ||||||
|  |   cilIndentIncrease, | ||||||
|  |   cilInputPower, | ||||||
|  |   cilItalic, | ||||||
|  |   cilJustifyCenter, | ||||||
|  |   cilJustifyLeft, | ||||||
|  |   cilLaptop, | ||||||
|  |   cilLayers, | ||||||
|  |   cilLightbulb, | ||||||
|  |   cilList, | ||||||
|  |   cilListNumbered, | ||||||
|  |   cilListRich, | ||||||
|  |   cilLocationPin, | ||||||
|  |   cilLockLocked, | ||||||
|  |   cilMagnifyingGlass, | ||||||
|  |   cilMap, | ||||||
|  |   cilMoon, | ||||||
|  |   cilNotes, | ||||||
|  |   cilOptions, | ||||||
|  |   cilPaperclip, | ||||||
|  |   cilPaperPlane, | ||||||
|  |   cilPencil, | ||||||
|  |   cilPeople, | ||||||
|  |   cilPhone, | ||||||
|  |   cilPrint, | ||||||
|  |   cilPuzzle, | ||||||
|  |   cilSave, | ||||||
|  |   cilScrubber, | ||||||
|  |   cilSettings, | ||||||
|  |   cilShare, | ||||||
|  |   cilShareAll, | ||||||
|  |   cilShareBoxed, | ||||||
|  |   cilShieldAlt, | ||||||
|  |   cilSpeech, | ||||||
|  |   cilSpeedometer, | ||||||
|  |   cilSpreadsheet, | ||||||
|  |   cilStar, | ||||||
|  |   cilSun, | ||||||
|  |   cilTags, | ||||||
|  |   cilTask, | ||||||
|  |   cilTrash, | ||||||
|  |   cilUnderline, | ||||||
|  |   cilUser, | ||||||
|  |   cilUserFemale, | ||||||
|  |   cilUserFollow, | ||||||
|  |   cilUserUnfollow, | ||||||
|  |   cilX, | ||||||
|  |   cilXCircle, | ||||||
|  |   cilWarning | ||||||
|  | }, { | ||||||
|  |   cifUs, | ||||||
|  |   cifBr, | ||||||
|  |   cifIn, | ||||||
|  |   cifFr, | ||||||
|  |   cifEs, | ||||||
|  |   cifPl | ||||||
|  | }, { | ||||||
|  |   cibSkype, | ||||||
|  |   cibFacebook, | ||||||
|  |   cibTwitter, | ||||||
|  |   cibLinkedin, | ||||||
|  |   cibFlickr, | ||||||
|  |   cibTumblr, | ||||||
|  |   cibXing, | ||||||
|  |   cibGithub, | ||||||
|  |   cibStackoverflow, | ||||||
|  |   cibYoutube, | ||||||
|  |   cibDribbble, | ||||||
|  |   cibInstagram, | ||||||
|  |   cibPinterest, | ||||||
|  |   cibVk, | ||||||
|  |   cibYahoo, | ||||||
|  |   cibBehance, | ||||||
|  |   cibReddit, | ||||||
|  |   cibVimeo, | ||||||
|  |   cibCcMastercard, | ||||||
|  |   cibCcVisa, | ||||||
|  |   cibStripe, | ||||||
|  |   cibPaypal, | ||||||
|  |   cibGooglePay, | ||||||
|  |   cibCcAmex | ||||||
|  | }) | ||||||
							
								
								
									
										30
									
								
								src/assets/icons/logo-negative.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/assets/icons/logo-negative.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | export const logoNegative = ['608 134', ` | ||||||
|  |   <title>coreui react pro logo</title> | ||||||
|  |   <g> | ||||||
|  |     <g style="fill:#80d0ff;"> | ||||||
|  |       <path d="M362.0177,90.1512,353.25,69.4149a.2507.2507,0,0,0-.2559-.1914H343.01a.2263.2263,0,0,0-.2559.2559V90.0233a.5657.5657,0,0,1-.64.64h-1.2163a.5652.5652,0,0,1-.64-.64V46.5028a.5655.5655,0,0,1,.64-.64H353.442a9.9792,9.9792,0,0,1,7.7437,3.2324A12.2,12.2,0,0,1,364.13,57.64a12.4389,12.4389,0,0,1-2.24,7.584,9.37,9.37,0,0,1-6.08,3.7441c-.1709.086-.2139.1915-.128.3194l8.7041,20.6084.064.2558q0,.5127-.5757.5118h-1.1523A.703.703,0,0,1,362.0177,90.1512ZM342.754,48.3593v18.496a.2259.2259,0,0,0,.2559.2559h10.3037a7.6713,7.6713,0,0,0,6.0166-2.5918,9.8807,9.8807,0,0,0,2.3037-6.8164,10.2875,10.2875,0,0,0-2.272-6.9756,7.6033,7.6033,0,0,0-6.0483-2.624H343.01A.2263.2263,0,0,0,342.754,48.3593Z"/> | ||||||
|  |       <path d="M401.3263,48.1034H381.2945a.2262.2262,0,0,0-.2558.2559v18.496a.2259.2259,0,0,0,.2558.2559h13.8238a.5664.5664,0,0,1,.6406.64v.96a.5663.5663,0,0,1-.6406.6406H381.2945a.2263.2263,0,0,0-.2558.2559v18.56a.2258.2258,0,0,0,.2558.2558h20.0318a.5671.5671,0,0,1,.6406.6407v.96a.566.566,0,0,1-.6406.64H379.1827a.5653.5653,0,0,1-.64-.64V46.5028a.5656.5656,0,0,1,.64-.64h22.1436a.5664.5664,0,0,1,.6406.64v.96A.5663.5663,0,0,1,401.3263,48.1034Z"/> | ||||||
|  |       <path d="M439.047,90.1512l-2.4317-8.832a.2971.2971,0,0,0-.32-.1924H419.5274a.2957.2957,0,0,0-.32.1924l-2.3681,8.7676a.6577.6577,0,0,1-.7036.5762H414.919a.5385.5385,0,0,1-.5756-.7041l12.0317-43.584a.6436.6436,0,0,1,.7041-.5117h1.6a.6442.6442,0,0,1,.7041.5117l12.16,43.584.0644.1923q0,.5127-.64.5118h-1.2163A.6428.6428,0,0,1,439.047,90.1512ZM419.9435,78.9188a.3031.3031,0,0,0,.2236.0967h15.4883a.3048.3048,0,0,0,.2236-.0967c.0645-.0635.0742-.1162.0322-.1592l-7.872-28.9287c-.043-.0849-.086-.1279-.128-.1279s-.0859.043-.1279.1279L419.9112,78.76C419.8683,78.8026,419.879,78.8553,419.9435,78.9188Z"/> | ||||||
|  |       <path d="M456.6017,87.911a11.6372,11.6372,0,0,1-3.3277-8.7041V57.1913a11.4158,11.4158,0,0,1,3.36-8.5762,12.0941,12.0941,0,0,1,8.8-3.2637,12.2566,12.2566,0,0,1,8.8643,3.2315,11.3927,11.3927,0,0,1,3.36,8.6084v.64a.5663.5663,0,0,1-.6406.6407l-1.28.0634q-.6408,0-.64-.5761v-.8321a9.289,9.289,0,0,0-2.6558-6.9121,10.6734,10.6734,0,0,0-14.0161,0,9.2854,9.2854,0,0,0-2.6563,6.9121V79.3993a9.2808,9.2808,0,0,0,2.6563,6.9121,10.67,10.67,0,0,0,14.0161,0,9.2843,9.2843,0,0,0,2.6558-6.9121v-.7686q0-.5757.64-.5752l1.28.0635a.5667.5667,0,0,1,.6406.6406v.5118a11.4952,11.4952,0,0,1-3.36,8.64,13.6227,13.6227,0,0,1-17.6963,0Z"/> | ||||||
|  |       <path d="M514.4376,46.5028v.96a.5658.5658,0,0,1-.64.6406H503.046a.2263.2263,0,0,0-.2559.2559v41.664a.566.566,0,0,1-.6406.64h-1.2158a.5652.5652,0,0,1-.64-.64V48.3593a.2266.2266,0,0,0-.2558-.2559H489.8619a.5656.5656,0,0,1-.64-.6406v-.96a.5656.5656,0,0,1,.64-.64H513.798A.5658.5658,0,0,1,514.4376,46.5028Z"/> | ||||||
|  |       <path d="M522.0665,89.5116a2.8385,2.8385,0,0,1-.8-2.0488,2.9194,2.9194,0,0,1,.8-2.1114,2.7544,2.7544,0,0,1,2.08-.832,2.8465,2.8465,0,0,1,2.9438,2.9434,2.7541,2.7541,0,0,1-.832,2.08,2.9221,2.9221,0,0,1-2.1118.8008A2.754,2.754,0,0,1,522.0665,89.5116Z"/> | ||||||
|  |       <path d="M542.4054,88.0077a11.3123,11.3123,0,0,1-3.2-8.416v-5.44a.5656.5656,0,0,1,.64-.64h1.2158a.5661.5661,0,0,1,.64.64v5.5039a9.1424,9.1424,0,0,0,2.5283,6.72,8.9745,8.9745,0,0,0,6.6875,2.5605,8.7908,8.7908,0,0,0,9.28-9.28V46.5028a.5655.5655,0,0,1,.64-.64h1.2163a.566.566,0,0,1,.64.64V79.5917a11.2545,11.2545,0,0,1-3.2325,8.416,13.0618,13.0618,0,0,1-17.0556,0Z"/> | ||||||
|  |       <path d="M580.35,88.1034a10.4859,10.4859,0,0,1-3.36-8.1279v-1.792a.5663.5663,0,0,1,.64-.6407h1.0884a.5668.5668,0,0,1,.64.6407v1.6a8.5459,8.5459,0,0,0,2.752,6.6562,10.5353,10.5353,0,0,0,7.36,2.4961,9.8719,9.8719,0,0,0,6.9761-2.3681,8.2161,8.2161,0,0,0,2.56-6.336,8.4,8.4,0,0,0-1.12-4.416,11.3812,11.3812,0,0,0-3.3281-3.3926,71.6714,71.6714,0,0,0-6.1763-3.7119,71.0479,71.0479,0,0,1-6.24-3.84,12.1711,12.1711,0,0,1-3.4238-3.68,10.2614,10.2614,0,0,1-1.28-5.3438,9.8579,9.8579,0,0,1,3.0718-7.7441,12.0122,12.0122,0,0,1,8.32-2.752q5.6954,0,8.96,3.1036a10.8251,10.8251,0,0,1,3.2642,8.2246v1.6a.5658.5658,0,0,1-.64.64h-1.1519a.5652.5652,0,0,1-.64-.64V56.8075a8.8647,8.8647,0,0,0-2.624-6.6885,9.9933,9.9933,0,0,0-7.232-2.5273,9.37,9.37,0,0,0-6.5278,2.1435,7.8224,7.8224,0,0,0-2.3682,6.1123,7.8006,7.8006,0,0,0,1.0244,4.16,10.387,10.387,0,0,0,3.0078,3.0391,62.8714,62.8714,0,0,0,5.9522,3.4882,71.0575,71.0575,0,0,1,6.72,4.2559,13.4674,13.4674,0,0,1,3.648,3.9365,10.049,10.049,0,0,1,1.28,5.1836,10.7177,10.7177,0,0,1-3.2637,8.1924q-3.2637,3.0717-8.832,3.0723Q583.71,91.1757,580.35,88.1034Z"/> | ||||||
|  |     </g> | ||||||
|  |  | ||||||
|  |     <g style="fill:#fff;"> | ||||||
|  |       <g> | ||||||
|  |         <path d="M99.835,36.0577l-39-22.5167a12,12,0,0,0-12,0l-39,22.5166a12.0339,12.0339,0,0,0-6,10.3924V91.4833a12.0333,12.0333,0,0,0,6,10.3923l39,22.5167a12,12,0,0,0,12,0l39-22.5167a12.0331,12.0331,0,0,0,6-10.3923V46.45A12.0334,12.0334,0,0,0,99.835,36.0577Zm-2,55.4256a4,4,0,0,1-2,3.4641l-39,22.5167a4.0006,4.0006,0,0,1-4,0l-39-22.5167a4,4,0,0,1-2-3.4641V46.45a4,4,0,0,1,2-3.4642l39-22.5166a4,4,0,0,1,4,0l39,22.5166a4,4,0,0,1,2,3.4642Z"/> | ||||||
|  |         <path d="M77.8567,82.0046h-2.866a4,4,0,0,0-1.9247.4934L55.7852,91.9833,35.835,80.4648V57.4872l19.95-11.5185,17.2893,9.4549a3.9993,3.9993,0,0,0,1.9192.4906h2.8632a2,2,0,0,0,2-2V51.2024a2,2,0,0,0-1.04-1.7547L59.628,38.9521a8.0391,8.0391,0,0,0-7.8428.09L31.8346,50.56a8.0246,8.0246,0,0,0-4,6.9287v22.976a8,8,0,0,0,4,6.9283l19.95,11.5186a8.0429,8.0429,0,0,0,7.8433.0879l19.19-10.5312a2,2,0,0,0,1.0378-1.7533v-2.71A2,2,0,0,0,77.8567,82.0046Z"/> | ||||||
|  |       </g> | ||||||
|  |       <g> | ||||||
|  |         <path d="M172.58,45.3618a15.0166,15.0166,0,0,0-15,14.9995V77.6387a15,15,0,0,0,30,0V60.3613A15.0166,15.0166,0,0,0,172.58,45.3618Zm7,32.2769a7,7,0,0,1-14,0V60.3613a7,7,0,0,1,14,0Z"/> | ||||||
|  |         <path d="M135.9138,53.4211a7.01,7.01,0,0,1,7.8681,6.0752.9894.9894,0,0,0,.9843.865h6.03a1.0108,1.0108,0,0,0,.9987-1.0971,15.0182,15.0182,0,0,0-15.7162-13.8837,15.2881,15.2881,0,0,0-14.2441,15.4163V77.2037A15.288,15.288,0,0,0,136.0792,92.62a15.0183,15.0183,0,0,0,15.7162-13.8842,1.0107,1.0107,0,0,0-.9987-1.0971h-6.03a.9894.9894,0,0,0-.9843.865,7.01,7.01,0,0,1-7.8679,6.0757,7.1642,7.1642,0,0,1-6.0789-7.1849V60.6057A7.1638,7.1638,0,0,1,135.9138,53.4211Z"/> | ||||||
|  |         <path d="M218.7572,72.9277a12.1585,12.1585,0,0,0,7.1843-11.0771V58.1494A12.1494,12.1494,0,0,0,213.7921,46H196.835a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h6a1,1,0,0,0,1-1V74h6.6216l7.9154,17.4138a1,1,0,0,0,.91.5862h6.5911a1,1,0,0,0,.91-1.4138Zm-.8157-11.0771A4.1538,4.1538,0,0,1,213.7926,66h-9.8511V54h9.8511a4.1538,4.1538,0,0,1,4.1489,4.1494Z"/> | ||||||
|  |         <path d="M260.835,46h-26a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h26a1,1,0,0,0,1-1V85a1,1,0,0,0-1-1h-19V72h13a1,1,0,0,0,1-1V65a1,1,0,0,0-1-1h-13V54h19a1,1,0,0,0,1-1V47A1,1,0,0,0,260.835,46Z"/> | ||||||
|  |         <path d="M298.835,46h-6a1,1,0,0,0-1,1V69.6475a7.0066,7.0066,0,1,1-14,0V47a1,1,0,0,0-1-1h-6a1,1,0,0,0-1,1V69.6475a15.0031,15.0031,0,1,0,30,0V47A1,1,0,0,0,298.835,46Z"/> | ||||||
|  |         <rect x="307.835" y="46" width="8" height="38" rx="1"/> | ||||||
|  |       </g> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | `] | ||||||
							
								
								
									
										29
									
								
								src/assets/icons/logo.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/assets/icons/logo.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | export const logo = ['608 134', ` | ||||||
|  |   <title>coreui react pro</title> | ||||||
|  |   <g> | ||||||
|  |     <g style="fill:#00a1ff"> | ||||||
|  |       <path d="M362.0177,90.1512,353.25,69.4149a.2507.2507,0,0,0-.2559-.1914H343.01a.2263.2263,0,0,0-.2559.2559V90.0233a.5657.5657,0,0,1-.64.64h-1.2163a.5652.5652,0,0,1-.64-.64V46.5028a.5655.5655,0,0,1,.64-.64H353.442a9.9792,9.9792,0,0,1,7.7437,3.2324A12.2,12.2,0,0,1,364.13,57.64a12.4389,12.4389,0,0,1-2.24,7.584,9.37,9.37,0,0,1-6.08,3.7441c-.1709.086-.2139.1915-.128.3194l8.7041,20.6084.064.2558q0,.5127-.5757.5118h-1.1523A.703.703,0,0,1,362.0177,90.1512ZM342.754,48.3593v18.496a.2259.2259,0,0,0,.2559.2559h10.3037a7.6713,7.6713,0,0,0,6.0166-2.5918,9.8807,9.8807,0,0,0,2.3037-6.8164,10.2875,10.2875,0,0,0-2.272-6.9756,7.6033,7.6033,0,0,0-6.0483-2.624H343.01A.2263.2263,0,0,0,342.754,48.3593Z"/> | ||||||
|  |       <path d="M401.3263,48.1034H381.2945a.2262.2262,0,0,0-.2558.2559v18.496a.2259.2259,0,0,0,.2558.2559h13.8238a.5664.5664,0,0,1,.6406.64v.96a.5663.5663,0,0,1-.6406.6406H381.2945a.2263.2263,0,0,0-.2558.2559v18.56a.2258.2258,0,0,0,.2558.2558h20.0318a.5671.5671,0,0,1,.6406.6407v.96a.566.566,0,0,1-.6406.64H379.1827a.5653.5653,0,0,1-.64-.64V46.5028a.5656.5656,0,0,1,.64-.64h22.1436a.5664.5664,0,0,1,.6406.64v.96A.5663.5663,0,0,1,401.3263,48.1034Z"/> | ||||||
|  |       <path d="M439.047,90.1512l-2.4317-8.832a.2971.2971,0,0,0-.32-.1924H419.5274a.2957.2957,0,0,0-.32.1924l-2.3681,8.7676a.6577.6577,0,0,1-.7036.5762H414.919a.5385.5385,0,0,1-.5756-.7041l12.0317-43.584a.6436.6436,0,0,1,.7041-.5117h1.6a.6442.6442,0,0,1,.7041.5117l12.16,43.584.0644.1923q0,.5127-.64.5118h-1.2163A.6428.6428,0,0,1,439.047,90.1512ZM419.9435,78.9188a.3031.3031,0,0,0,.2236.0967h15.4883a.3048.3048,0,0,0,.2236-.0967c.0645-.0635.0742-.1162.0322-.1592l-7.872-28.9287c-.043-.0849-.086-.1279-.128-.1279s-.0859.043-.1279.1279L419.9112,78.76C419.8683,78.8026,419.879,78.8553,419.9435,78.9188Z"/> | ||||||
|  |       <path d="M456.6017,87.911a11.6372,11.6372,0,0,1-3.3277-8.7041V57.1913a11.4158,11.4158,0,0,1,3.36-8.5762,12.0941,12.0941,0,0,1,8.8-3.2637,12.2566,12.2566,0,0,1,8.8643,3.2315,11.3927,11.3927,0,0,1,3.36,8.6084v.64a.5663.5663,0,0,1-.6406.6407l-1.28.0634q-.6408,0-.64-.5761v-.8321a9.289,9.289,0,0,0-2.6558-6.9121,10.6734,10.6734,0,0,0-14.0161,0,9.2854,9.2854,0,0,0-2.6563,6.9121V79.3993a9.2808,9.2808,0,0,0,2.6563,6.9121,10.67,10.67,0,0,0,14.0161,0,9.2843,9.2843,0,0,0,2.6558-6.9121v-.7686q0-.5757.64-.5752l1.28.0635a.5667.5667,0,0,1,.6406.6406v.5118a11.4952,11.4952,0,0,1-3.36,8.64,13.6227,13.6227,0,0,1-17.6963,0Z"/> | ||||||
|  |       <path d="M514.4376,46.5028v.96a.5658.5658,0,0,1-.64.6406H503.046a.2263.2263,0,0,0-.2559.2559v41.664a.566.566,0,0,1-.6406.64h-1.2158a.5652.5652,0,0,1-.64-.64V48.3593a.2266.2266,0,0,0-.2558-.2559H489.8619a.5656.5656,0,0,1-.64-.6406v-.96a.5656.5656,0,0,1,.64-.64H513.798A.5658.5658,0,0,1,514.4376,46.5028Z"/> | ||||||
|  |       <path d="M522.0665,89.5116a2.8385,2.8385,0,0,1-.8-2.0488,2.9194,2.9194,0,0,1,.8-2.1114,2.7544,2.7544,0,0,1,2.08-.832,2.8465,2.8465,0,0,1,2.9438,2.9434,2.7541,2.7541,0,0,1-.832,2.08,2.9221,2.9221,0,0,1-2.1118.8008A2.754,2.754,0,0,1,522.0665,89.5116Z"/> | ||||||
|  |       <path d="M542.4054,88.0077a11.3123,11.3123,0,0,1-3.2-8.416v-5.44a.5656.5656,0,0,1,.64-.64h1.2158a.5661.5661,0,0,1,.64.64v5.5039a9.1424,9.1424,0,0,0,2.5283,6.72,8.9745,8.9745,0,0,0,6.6875,2.5605,8.7908,8.7908,0,0,0,9.28-9.28V46.5028a.5655.5655,0,0,1,.64-.64h1.2163a.566.566,0,0,1,.64.64V79.5917a11.2545,11.2545,0,0,1-3.2325,8.416,13.0618,13.0618,0,0,1-17.0556,0Z"/> | ||||||
|  |       <path d="M580.35,88.1034a10.4859,10.4859,0,0,1-3.36-8.1279v-1.792a.5663.5663,0,0,1,.64-.6407h1.0884a.5668.5668,0,0,1,.64.6407v1.6a8.5459,8.5459,0,0,0,2.752,6.6562,10.5353,10.5353,0,0,0,7.36,2.4961,9.8719,9.8719,0,0,0,6.9761-2.3681,8.2161,8.2161,0,0,0,2.56-6.336,8.4,8.4,0,0,0-1.12-4.416,11.3812,11.3812,0,0,0-3.3281-3.3926,71.6714,71.6714,0,0,0-6.1763-3.7119,71.0479,71.0479,0,0,1-6.24-3.84,12.1711,12.1711,0,0,1-3.4238-3.68,10.2614,10.2614,0,0,1-1.28-5.3438,9.8579,9.8579,0,0,1,3.0718-7.7441,12.0122,12.0122,0,0,1,8.32-2.752q5.6954,0,8.96,3.1036a10.8251,10.8251,0,0,1,3.2642,8.2246v1.6a.5658.5658,0,0,1-.64.64h-1.1519a.5652.5652,0,0,1-.64-.64V56.8075a8.8647,8.8647,0,0,0-2.624-6.6885,9.9933,9.9933,0,0,0-7.232-2.5273,9.37,9.37,0,0,0-6.5278,2.1435,7.8224,7.8224,0,0,0-2.3682,6.1123,7.8006,7.8006,0,0,0,1.0244,4.16,10.387,10.387,0,0,0,3.0078,3.0391,62.8714,62.8714,0,0,0,5.9522,3.4882,71.0575,71.0575,0,0,1,6.72,4.2559,13.4674,13.4674,0,0,1,3.648,3.9365,10.049,10.049,0,0,1,1.28,5.1836,10.7177,10.7177,0,0,1-3.2637,8.1924q-3.2637,3.0717-8.832,3.0723Q583.71,91.1757,580.35,88.1034Z"/> | ||||||
|  |     </g> | ||||||
|  |     <g style="fill:#3c4b64"> | ||||||
|  |       <g> | ||||||
|  |         <path d="M99.835,36.0577l-39-22.5167a12,12,0,0,0-12,0l-39,22.5166a12.0339,12.0339,0,0,0-6,10.3924V91.4833a12.0333,12.0333,0,0,0,6,10.3923l39,22.5167a12,12,0,0,0,12,0l39-22.5167a12.0331,12.0331,0,0,0,6-10.3923V46.45A12.0334,12.0334,0,0,0,99.835,36.0577Zm-2,55.4256a4,4,0,0,1-2,3.4641l-39,22.5167a4.0006,4.0006,0,0,1-4,0l-39-22.5167a4,4,0,0,1-2-3.4641V46.45a4,4,0,0,1,2-3.4642l39-22.5166a4,4,0,0,1,4,0l39,22.5166a4,4,0,0,1,2,3.4642Z"/> | ||||||
|  |         <path d="M77.8567,82.0046h-2.866a4,4,0,0,0-1.9247.4934L55.7852,91.9833,35.835,80.4648V57.4872l19.95-11.5185,17.2893,9.4549a3.9993,3.9993,0,0,0,1.9192.4906h2.8632a2,2,0,0,0,2-2V51.2024a2,2,0,0,0-1.04-1.7547L59.628,38.9521a8.0391,8.0391,0,0,0-7.8428.09L31.8346,50.56a8.0246,8.0246,0,0,0-4,6.9287v22.976a8,8,0,0,0,4,6.9283l19.95,11.5186a8.0429,8.0429,0,0,0,7.8433.0879l19.19-10.5312a2,2,0,0,0,1.0378-1.7533v-2.71A2,2,0,0,0,77.8567,82.0046Z"/> | ||||||
|  |       </g> | ||||||
|  |       <g> | ||||||
|  |         <path d="M172.58,45.3618a15.0166,15.0166,0,0,0-15,14.9995V77.6387a15,15,0,0,0,30,0V60.3613A15.0166,15.0166,0,0,0,172.58,45.3618Zm7,32.2769a7,7,0,0,1-14,0V60.3613a7,7,0,0,1,14,0Z"/> | ||||||
|  |         <path d="M135.9138,53.4211a7.01,7.01,0,0,1,7.8681,6.0752.9894.9894,0,0,0,.9843.865h6.03a1.0108,1.0108,0,0,0,.9987-1.0971,15.0182,15.0182,0,0,0-15.7162-13.8837,15.2881,15.2881,0,0,0-14.2441,15.4163V77.2037A15.288,15.288,0,0,0,136.0792,92.62a15.0183,15.0183,0,0,0,15.7162-13.8842,1.0107,1.0107,0,0,0-.9987-1.0971h-6.03a.9894.9894,0,0,0-.9843.865,7.01,7.01,0,0,1-7.8679,6.0757,7.1642,7.1642,0,0,1-6.0789-7.1849V60.6057A7.1638,7.1638,0,0,1,135.9138,53.4211Z"/> | ||||||
|  |         <path d="M218.7572,72.9277a12.1585,12.1585,0,0,0,7.1843-11.0771V58.1494A12.1494,12.1494,0,0,0,213.7921,46H196.835a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h6a1,1,0,0,0,1-1V74h6.6216l7.9154,17.4138a1,1,0,0,0,.91.5862h6.5911a1,1,0,0,0,.91-1.4138Zm-.8157-11.0771A4.1538,4.1538,0,0,1,213.7926,66h-9.8511V54h9.8511a4.1538,4.1538,0,0,1,4.1489,4.1494Z"/> | ||||||
|  |         <path d="M260.835,46h-26a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h26a1,1,0,0,0,1-1V85a1,1,0,0,0-1-1h-19V72h13a1,1,0,0,0,1-1V65a1,1,0,0,0-1-1h-13V54h19a1,1,0,0,0,1-1V47A1,1,0,0,0,260.835,46Z"/> | ||||||
|  |         <path d="M298.835,46h-6a1,1,0,0,0-1,1V69.6475a7.0066,7.0066,0,1,1-14,0V47a1,1,0,0,0-1-1h-6a1,1,0,0,0-1,1V69.6475a15.0031,15.0031,0,1,0,30,0V47A1,1,0,0,0,298.835,46Z"/> | ||||||
|  |         <rect x="307.835" y="46" width="8" height="38" rx="1"/> | ||||||
|  |       </g> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | `] | ||||||
							
								
								
									
										9
									
								
								src/assets/icons/sygnet.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/assets/icons/sygnet.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | export const sygnet = ['160 160', ` | ||||||
|  |   <title>coreui logo</title> | ||||||
|  |   <g> | ||||||
|  |     <g style="fill:#fff;"> | ||||||
|  |       <path d="M125,47.091,86,24.5743a12,12,0,0,0-12,0L35,47.091a12.0336,12.0336,0,0,0-6,10.3923v45.0334a12.0335,12.0335,0,0,0,6,10.3923l39,22.5166a11.9993,11.9993,0,0,0,12,0l39-22.5166a12.0335,12.0335,0,0,0,6-10.3923V57.4833A12.0336,12.0336,0,0,0,125,47.091Zm-2,55.4257a4,4,0,0,1-2,3.464L82,128.4974a4,4,0,0,1-4,0L39,105.9807a4,4,0,0,1-2-3.464V57.4833a4,4,0,0,1,2-3.4641L78,31.5025a4,4,0,0,1,4,0l39,22.5167a4,4,0,0,1,2,3.4641Z"/> | ||||||
|  |       <path d="M103.0216,93.0379h-2.866a4,4,0,0,0-1.9246.4935L80.95,103.0167,61,91.4981V68.5206L80.95,57.002l17.2894,9.455a4,4,0,0,0,1.9192.4905h2.8632a2,2,0,0,0,2-2V62.2357a2,2,0,0,0-1.04-1.7547L84.793,49.9854a8.0391,8.0391,0,0,0-7.8428.09L57,61.5929A8.0243,8.0243,0,0,0,53,68.5216v22.976a8,8,0,0,0,4,6.9283l19.95,11.5185a8.0422,8.0422,0,0,0,7.8433.0879l19.19-10.5311a2,2,0,0,0,1.0378-1.7534v-2.71A2,2,0,0,0,103.0216,93.0379Z"/> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | `] | ||||||
							
								
								
									
										35
									
								
								src/components/DeviceActions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/components/DeviceActions.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import { | ||||||
|  |     CButton, | ||||||
|  |     CCard, | ||||||
|  |     CCardHeader, | ||||||
|  |     CCardBody, | ||||||
|  |     CRow, | ||||||
|  |     CCol | ||||||
|  |   } from '@coreui/react' | ||||||
|  | import { useSelector } from 'react-redux'; | ||||||
|  |  | ||||||
|  | const DeviceActions = () => { | ||||||
|  |     let selectedDevice = useSelector(state => state.selectedDevice); | ||||||
|  |     console.log(selectedDevice); | ||||||
|  |     return ( | ||||||
|  |         <CCard> | ||||||
|  |             <CCardHeader> | ||||||
|  |                 Device Actions | ||||||
|  |             </CCardHeader> | ||||||
|  |             <CCardBody> | ||||||
|  |                 <CRow> | ||||||
|  |                     <CCol> | ||||||
|  |                         <CButton block color="primary">Reboot</CButton> | ||||||
|  |                     </CCol> | ||||||
|  |                     <CCol> | ||||||
|  |                         <CButton block color="primary">Blink</CButton> | ||||||
|  |                     </CCol> | ||||||
|  |  | ||||||
|  |                 </CRow> | ||||||
|  |             </CCardBody> | ||||||
|  |         </CCard> | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default DeviceActions | ||||||
							
								
								
									
										207
									
								
								src/components/DeviceConfiguration.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								src/components/DeviceConfiguration.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | |||||||
|  | import React, { useState } from 'react' | ||||||
|  | import { | ||||||
|  |     CCard, | ||||||
|  |     CCardHeader, | ||||||
|  |     CCardBody, | ||||||
|  |     CFormGroup, | ||||||
|  |     CCol, | ||||||
|  |     CLabel, | ||||||
|  |     CForm, | ||||||
|  |     CInput, | ||||||
|  |     CCollapse, | ||||||
|  |     CCardFooter, | ||||||
|  |     CButton | ||||||
|  | } from '@coreui/react' | ||||||
|  | import { useSelector } from 'react-redux'; | ||||||
|  | import { cleanTimestamp} from '../utils/helper'; | ||||||
|  |  | ||||||
|  | const DeviceConfiguration = () => { | ||||||
|  |     const [collapse, setCollapse] = useState(false) | ||||||
|  |     let device = useSelector(state => state.selectedDevice); | ||||||
|  |  | ||||||
|  |     const toggle = (e) => { | ||||||
|  |         setCollapse(!collapse); | ||||||
|  |         e.preventDefault(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if(device){ | ||||||
|  |         return ( | ||||||
|  |             <CCard> | ||||||
|  |                 <CCardHeader> | ||||||
|  |                     Device #{device.serialNumber} Configuration | ||||||
|  |                 </CCardHeader> | ||||||
|  |                 <CCardBody> | ||||||
|  |                     <CForm action="" method="post" encType="multipart/form-data" className="form-horizontal"> | ||||||
|  |                         <CFormGroup row> | ||||||
|  |                             <CCol md="3"> | ||||||
|  |                                 <CLabel>UUID : </CLabel> | ||||||
|  |                             </CCol> | ||||||
|  |                             <CCol xs="12" md="9"> | ||||||
|  |                                 {device.UUID } | ||||||
|  |                             </CCol> | ||||||
|  |                         </CFormGroup> | ||||||
|  |                         <CFormGroup row> | ||||||
|  |                             <CCol md="3"> | ||||||
|  |                                 <CLabel>Serial Number : </CLabel> | ||||||
|  |                             </CCol> | ||||||
|  |                             <CCol xs="12" md="9"> | ||||||
|  |                                 {device.serialNumber } | ||||||
|  |                             </CCol> | ||||||
|  |                         </CFormGroup> | ||||||
|  |                         <CFormGroup row> | ||||||
|  |                                 <CCol md="3"> | ||||||
|  |                                     <CLabel>Device Type : </CLabel> | ||||||
|  |                                 </CCol> | ||||||
|  |                                 <CCol xs="12" md="9"> | ||||||
|  |                                     { device.deviceType } | ||||||
|  |                                 </CCol> | ||||||
|  |                             </CFormGroup> | ||||||
|  |                         <CFormGroup row> | ||||||
|  |                             <CCol md="3"> | ||||||
|  |                                 <CLabel>Last Configuration Change : </CLabel> | ||||||
|  |                             </CCol> | ||||||
|  |                             <CCol xs="12" md="9"> | ||||||
|  |                                 {cleanTimestamp(device.lastConfigurationChange) } | ||||||
|  |                             </CCol> | ||||||
|  |                         </CFormGroup> | ||||||
|  |                         <CFormGroup row> | ||||||
|  |                             <CCol md="3"> | ||||||
|  |                                 <CLabel>MAC address :</CLabel> | ||||||
|  |                             </CCol> | ||||||
|  |                             <CCol xs="12" md="9"> | ||||||
|  |                                 { device.macAddress } | ||||||
|  |                             </CCol> | ||||||
|  |                         </CFormGroup> | ||||||
|  |                         <CCollapse show={collapse}> | ||||||
|  |                             <CFormGroup row> | ||||||
|  |                                 <CCol md="3"> | ||||||
|  |                                     <CLabel>Created : </CLabel> | ||||||
|  |                                 </CCol> | ||||||
|  |                                 <CCol xs="12" md="9"> | ||||||
|  |                                     { cleanTimestamp(device.createdTimestamp) } | ||||||
|  |                                 </CCol> | ||||||
|  |                             </CFormGroup> | ||||||
|  |                             <CFormGroup row> | ||||||
|  |                                 <CCol md="3"> | ||||||
|  |                                     <CLabel>Last Configuration Download : </CLabel> | ||||||
|  |                                 </CCol> | ||||||
|  |                                 <CCol xs="12" md="9"> | ||||||
|  |                                     {cleanTimestamp(device.lastConfigurationDownload) } | ||||||
|  |                                 </CCol> | ||||||
|  |                             </CFormGroup> | ||||||
|  |                             <CFormGroup row> | ||||||
|  |                                 <CCol md="3"> | ||||||
|  |                                     <CLabel>Manufacturer :</CLabel> | ||||||
|  |                                 </CCol> | ||||||
|  |                                 <CCol xs="12" md="9"> | ||||||
|  |                                     { device.manufacturer } | ||||||
|  |                                 </CCol> | ||||||
|  |                             </CFormGroup> | ||||||
|  |                             <CFormGroup row> | ||||||
|  |                                 <CCol md="3"> | ||||||
|  |                                     <CLabel htmlFor="text-input">Notes :</CLabel> | ||||||
|  |                                 </CCol> | ||||||
|  |                                 <CCol xs="12" md="9"> | ||||||
|  |                                     <CInput id="text-input" name="text-input" placeholder={device.notes} /> | ||||||
|  |                                 </CCol> | ||||||
|  |                             </CFormGroup> | ||||||
|  |                             <CFormGroup row> | ||||||
|  |                                 <CCol md="3"> | ||||||
|  |                                     <CLabel>Owner :</CLabel> | ||||||
|  |                                 </CCol> | ||||||
|  |                                 <CCol xs="12" md="9"> | ||||||
|  |                                     { device.owner } | ||||||
|  |                                 </CCol> | ||||||
|  |                             </CFormGroup> | ||||||
|  |                             <CFormGroup row> | ||||||
|  |                                 <CCol md="3"> | ||||||
|  |                                     <CLabel>Location :</CLabel> | ||||||
|  |                                 </CCol> | ||||||
|  |                                 <CCol xs="12" md="9"> | ||||||
|  |                                     { device.location } | ||||||
|  |                                 </CCol> | ||||||
|  |                             </CFormGroup> | ||||||
|  |                         </CCollapse> | ||||||
|  |                         <CCardFooter> | ||||||
|  |                             <CButton | ||||||
|  |                             color="primary" | ||||||
|  |                             onClick={toggle} | ||||||
|  |                             className={'mb-1'} | ||||||
|  |                             >More details</CButton> | ||||||
|  |                         </CCardFooter> | ||||||
|  |                     </CForm> | ||||||
|  |                 </CCardBody> | ||||||
|  |             </CCard> | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ( | ||||||
|  |             <CCard> | ||||||
|  |                 <CCardHeader> | ||||||
|  |                     Device Configuration | ||||||
|  |                 </CCardHeader> | ||||||
|  |                 <CCardBody> | ||||||
|  |                 </CCardBody> | ||||||
|  |             </CCard> | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export default DeviceConfiguration | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  | ||||||
|  | location ???? | ||||||
|  |  | ||||||
|  | configuration | ||||||
|  |     log | ||||||
|  |         _log_hostname | ||||||
|  |         _log_ip | ||||||
|  |         _log_port | ||||||
|  |         _log_proto | ||||||
|  |         _log_size | ||||||
|  |     network (is a list) | ||||||
|  |         cfg | ||||||
|  |             proto | ||||||
|  |  | ||||||
|  |             OROROROR | ||||||
|  |  | ||||||
|  |             peeraddr | ||||||
|  |             vid | ||||||
|  |  | ||||||
|  |             OROROROR | ||||||
|  |  | ||||||
|  |             dhcp | ||||||
|  |                 leasetime | ||||||
|  |                 limit | ||||||
|  |                 start | ||||||
|  |             ip6assign | ||||||
|  |             ipaddr | ||||||
|  |             leases (is a list) | ||||||
|  |                 hostname | ||||||
|  |                 ip | ||||||
|  |                 mac | ||||||
|  |             mtu | ||||||
|  |             netmask | ||||||
|  |             proto | ||||||
|  |  | ||||||
|  |         mode | ||||||
|  |         vlan (sometimes) | ||||||
|  |      | ||||||
|  |     ntp | ||||||
|  |         enable_server | ||||||
|  |         enabled | ||||||
|  |         server (list of strings) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | */ | ||||||
							
								
								
									
										59
									
								
								src/components/DeviceHealth.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/components/DeviceHealth.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import { | ||||||
|  |     CWidgetProgressIcon, | ||||||
|  |     CWidgetDropdown, | ||||||
|  |     CDropdown, | ||||||
|  |     CDropdownToggle, | ||||||
|  |     CDropdownItem, | ||||||
|  |     CDropdownMenu, | ||||||
|  |     CCardFooter, | ||||||
|  |     CLink, | ||||||
|  |     CProgressBar | ||||||
|  | } from '@coreui/react' | ||||||
|  | import CIcon from '@coreui/icons-react' | ||||||
|  | import { cilHeart, cilSettings } from '@coreui/icons'; | ||||||
|  | import { useSelector } from 'react-redux'; | ||||||
|  |  | ||||||
|  | const healthPopoverContent = "100%: Perfect 90%-99%: Good 0%-90%: Bad"; | ||||||
|  |  | ||||||
|  | const DeviceHealth = () => { | ||||||
|  |     let selectedDevice = useSelector(state => state.selectedDevice); | ||||||
|  |     let sanityLevel; | ||||||
|  |     let barColor; | ||||||
|  |  | ||||||
|  |     if(selectedDevice && selectedDevice.healthChecks && selectedDevice.healthChecks.length > 0){ | ||||||
|  |         sanityLevel = selectedDevice.healthChecks[0].sanity; | ||||||
|  |  | ||||||
|  |         if(sanityLevel === 100) | ||||||
|  |             barColor = "gradient-success"; | ||||||
|  |         else if (sanityLevel >= 90) | ||||||
|  |             barColor = "gradient-warning"; | ||||||
|  |         else | ||||||
|  |             barColor = "gradient-danger"; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ( | ||||||
|  |  | ||||||
|  |             <CWidgetProgressIcon | ||||||
|  |                 header={sanityLevel ? `${sanityLevel}%` : 'Unknown'} | ||||||
|  |                 text="Device Health" | ||||||
|  |                 value={sanityLevel ?? 100} | ||||||
|  |                 color={barColor} | ||||||
|  |                 inverse | ||||||
|  |             > | ||||||
|  |                 <CDropdown> | ||||||
|  |                     {/* Need inline styling because CDropdownToggle does not take into account the | ||||||
|  |                     parent's inverse value*/} | ||||||
|  |                     <CDropdownToggle style={{color: 'white'}}> | ||||||
|  |                         <CIcon content={cilSettings}/> | ||||||
|  |                     </CDropdownToggle> | ||||||
|  |                     <CDropdownMenu placement="bottom-end"> | ||||||
|  |                         <CDropdownItem>View Logs</CDropdownItem> | ||||||
|  |                     </CDropdownMenu> | ||||||
|  |                 </CDropdown> | ||||||
|  |             </CWidgetProgressIcon> | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default DeviceHealth | ||||||
							
								
								
									
										220
									
								
								src/components/DeviceList.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								src/components/DeviceList.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,220 @@ | |||||||
|  | import React, { useEffect, useState, useCallback } from 'react' | ||||||
|  | import { | ||||||
|  |   CBadge, | ||||||
|  |   CCardBody, | ||||||
|  |   CDataTable, | ||||||
|  |   CCollapse, | ||||||
|  |   CButton, | ||||||
|  |   CLink | ||||||
|  | } from '@coreui/react' | ||||||
|  | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||||
|  | import { faSync } from '@fortawesome/free-solid-svg-icons' | ||||||
|  | import { getToken } from '../utils/authHelper'; | ||||||
|  | import axiosInstance from '../utils/axiosInstance'; | ||||||
|  |  | ||||||
|  | const DeviceList = () => { | ||||||
|  |   const [devices, setDevices] = useState([]); | ||||||
|  |   const [details, setDetails] = useState([]); | ||||||
|  |   const [loading, setLoading] = useState(true); | ||||||
|  |   const [lastRefresh, setLastRefresh] = useState([]); | ||||||
|  |  | ||||||
|  |   //Loading the devices | ||||||
|  |   const refreshDevices = useCallback(() => { | ||||||
|  |     const token = getToken(); | ||||||
|  |  | ||||||
|  |     const headers = { | ||||||
|  |         'Accept': 'application/json', | ||||||
|  |         'Authorization': `Bearer ${token}` | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     axiosInstance.get('/devices', { | ||||||
|  |         headers: headers | ||||||
|  |     }) | ||||||
|  |     .then((response) => { | ||||||
|  |       const date = new Date(); | ||||||
|  |       const dateAsString = date.toLocaleString(); | ||||||
|  |       setLastRefresh(dateAsString); | ||||||
|  |       addStatusToDeviceList(response.data.devices); | ||||||
|  |     }) | ||||||
|  |     .catch(error => { | ||||||
|  |       setLoading(false); | ||||||
|  |       console.log(error.response); | ||||||
|  |     }); | ||||||
|  |   }, []); | ||||||
|  |    | ||||||
|  |   //Getting the status for each device | ||||||
|  |   const addStatusToDeviceList = (devices) => { | ||||||
|  |     const token = getToken(); | ||||||
|  |      | ||||||
|  |     const headers = { | ||||||
|  |         'Accept': 'application/json', | ||||||
|  |         'Authorization': `Bearer ${token}` | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     for(let i = 0; i< devices.length; i++){ | ||||||
|  |       axiosInstance.get(`/device/${devices[i].serialNumber}/status`, { | ||||||
|  |         headers: headers | ||||||
|  |       }) | ||||||
|  |       .then((response) => { | ||||||
|  |           //Merging the device object in the array with the one we received from the API | ||||||
|  |           devices[i] = {...devices[i], ...response.data}; | ||||||
|  |           devices[i].ipAddress = devices[i].ipAddress.substr(0, devices[i].ipAddress.indexOf(':')); | ||||||
|  |           setDevices(devices); | ||||||
|  |       }) | ||||||
|  |       .catch(error => { | ||||||
|  |           setDevices(devices); | ||||||
|  |           setLoading(false); | ||||||
|  |           console.log(error.response); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //Function called from the button on the table so that a user can see more details | ||||||
|  |   const toggleDetails = (index) => { | ||||||
|  |     const position = details.indexOf(index) | ||||||
|  |     let newDetails = details.slice() | ||||||
|  |     if (position !== -1) { | ||||||
|  |       newDetails.splice(position, 1) | ||||||
|  |     } else { | ||||||
|  |       newDetails = [...details, index] | ||||||
|  |     } | ||||||
|  |     setDetails(newDetails) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   //refreshDevice() has a semicolon after to make it run once on component loading | ||||||
|  |   useEffect(() => {refreshDevices();},[refreshDevices]); | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <DeviceListDisplay  | ||||||
|  |       devices={devices}  | ||||||
|  |       refresh={refreshDevices}  | ||||||
|  |       toggleDetails={toggleDetails}  | ||||||
|  |       details={details} | ||||||
|  |       loading={loading}  | ||||||
|  |       lastRefresh={lastRefresh} | ||||||
|  |     /> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const DeviceListDisplay = ({ devices, refresh, toggleDetails, details, loading, lastRefresh }) => { | ||||||
|  |   const columns = [ | ||||||
|  |     { key: 'serialNumber'}, | ||||||
|  |     { key: 'UUID'}, | ||||||
|  |     { key: 'lastConfigurationChange'}, | ||||||
|  |     { key: 'lastConfigurationDownload'}, | ||||||
|  |     { key: 'deviceType'}, | ||||||
|  |     { key: 'connected'}, | ||||||
|  |     { key: 'txBytes'}, | ||||||
|  |     { key: 'rxBytes'}, | ||||||
|  |     { key: 'ipAddress'}, | ||||||
|  |     { | ||||||
|  |       key: 'show_details', | ||||||
|  |       label: '', | ||||||
|  |       _style: { width: '1%' }, | ||||||
|  |       sorter: false, | ||||||
|  |       filter: false | ||||||
|  |     } | ||||||
|  |   ]; | ||||||
|  |  | ||||||
|  |   const getStatusBadge = (status)=>{ | ||||||
|  |     if(status){ | ||||||
|  |       return 'success'; | ||||||
|  |     } | ||||||
|  |     return 'danger'; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   return ( | ||||||
|  |     <> | ||||||
|  |     <div className='row'> | ||||||
|  |       <div className='col'> | ||||||
|  |       <CButton onClick={refresh}> | ||||||
|  |             <FontAwesomeIcon icon={faSync} color='#007bff' size="2x"/> | ||||||
|  |         </CButton> | ||||||
|  |       </div> | ||||||
|  |       <div className='col'><div className='form-inline justify-content-sm-end'> | ||||||
|  |           Last refresh : {lastRefresh} | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <CDataTable | ||||||
|  |       items={devices} | ||||||
|  |       fields={columns} | ||||||
|  |       columnFilter | ||||||
|  |       itemsPerPageSelect | ||||||
|  |       itemsPerPage={10} | ||||||
|  |       hover | ||||||
|  |       sorter | ||||||
|  |       pagination | ||||||
|  |       loading = {loading} | ||||||
|  |       //loadingSlot | ||||||
|  |       scopedSlots = {{ | ||||||
|  |         'lastConfigurationChange': | ||||||
|  |         (item)=>( | ||||||
|  |           <td> | ||||||
|  |             {item.lastConfigurationChange.replace('T', ' ').replace('Z', '')} | ||||||
|  |           </td> | ||||||
|  |         ), | ||||||
|  |         'lastConfigurationDownload': | ||||||
|  |         (item)=>( | ||||||
|  |           <td> | ||||||
|  |             {item.lastConfigurationDownload.replace('T', ' ').replace('Z', '')} | ||||||
|  |           </td> | ||||||
|  |         ), | ||||||
|  |         'connected': | ||||||
|  |           (item)=>( | ||||||
|  |             <td> | ||||||
|  |               <CBadge color={getStatusBadge(item.connected)}> | ||||||
|  |                 {item.connected ? 'Connected' : 'Not connected'} | ||||||
|  |               </CBadge> | ||||||
|  |             </td> | ||||||
|  |           ), | ||||||
|  |         'show_details': | ||||||
|  |           (item, index)=>{ | ||||||
|  |             return ( | ||||||
|  |               <td className="py-2"> | ||||||
|  |                 <CButton | ||||||
|  |                   color="primary" | ||||||
|  |                   variant="outline" | ||||||
|  |                   shape="square" | ||||||
|  |                   size="sm" | ||||||
|  |                   onClick={()=>{toggleDetails(index)}} | ||||||
|  |                 > | ||||||
|  |                   {details.includes(index) ? 'Hide' : 'Show'} | ||||||
|  |                 </CButton> | ||||||
|  |               </td> | ||||||
|  |               ) | ||||||
|  |           }, | ||||||
|  |         'details': | ||||||
|  |             (item, index)=>{ | ||||||
|  |               return ( | ||||||
|  |               <CCollapse show={details.includes(index)}> | ||||||
|  |                 <CCardBody> | ||||||
|  |                   <h4> | ||||||
|  |                     {item.notes} | ||||||
|  |                   </h4> | ||||||
|  |                   <p className="text-muted">Last configuration change: {item.lastConfigurationChange.replace('T', ' ').replace('Z', '')}</p> | ||||||
|  |                   <CLink  | ||||||
|  |                     className="c-subheader-nav-link"  | ||||||
|  |                     aria-current="page"  | ||||||
|  |                     to={() => `/devices/${item.serialNumber}`} | ||||||
|  |                   >  | ||||||
|  |                     <CButton size="sm" color="info"> | ||||||
|  |                       Device Details | ||||||
|  |                     </CButton> | ||||||
|  |                   </CLink> | ||||||
|  |                    | ||||||
|  |                   <CButton size="sm" color="danger" className="ml-1"> | ||||||
|  |                     Reboot | ||||||
|  |                   </CButton> | ||||||
|  |                 </CCardBody> | ||||||
|  |               </CCollapse> | ||||||
|  |             ) | ||||||
|  |           } | ||||||
|  |       }} | ||||||
|  |     /> | ||||||
|  |     </> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export default DeviceList; | ||||||
							
								
								
									
										45
									
								
								src/containers/TheContent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/containers/TheContent.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | import React, { Suspense } from 'react' | ||||||
|  | import { | ||||||
|  |   Redirect, | ||||||
|  |   Route, | ||||||
|  |   Switch | ||||||
|  | } from 'react-router-dom' | ||||||
|  | import { CContainer, CFade } from '@coreui/react' | ||||||
|  | import routes from '../routes' | ||||||
|  |    | ||||||
|  | const loading = ( | ||||||
|  |   <div className="pt-3 text-center"> | ||||||
|  |     <div className="sk-spinner sk-spinner-pulse"></div> | ||||||
|  |   </div> | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const TheContent = () => { | ||||||
|  |   return ( | ||||||
|  |     <main className="c-main"> | ||||||
|  |       <CContainer fluid> | ||||||
|  |         <Suspense fallback={loading}> | ||||||
|  |           <Switch> | ||||||
|  |             { | ||||||
|  |             routes.map((route, idx) => { | ||||||
|  |               return route.component && ( | ||||||
|  |                 <Route | ||||||
|  |                   key={idx} | ||||||
|  |                   path={route.path} | ||||||
|  |                   exact={route.exact} | ||||||
|  |                   name={route.name} | ||||||
|  |                   render={props => ( | ||||||
|  |                     <CFade> | ||||||
|  |                       <route.component {...props} /> | ||||||
|  |                     </CFade> | ||||||
|  |                   )} /> | ||||||
|  |               ) | ||||||
|  |             })} | ||||||
|  |             <Redirect from="/" to="/devices" /> | ||||||
|  |           </Switch> | ||||||
|  |         </Suspense> | ||||||
|  |       </CContainer> | ||||||
|  |     </main> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default React.memo(TheContent) | ||||||
							
								
								
									
										19
									
								
								src/containers/TheFooter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/containers/TheFooter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import { CFooter } from '@coreui/react' | ||||||
|  |  | ||||||
|  | const TheFooter = () => { | ||||||
|  |   return ( | ||||||
|  |     <CFooter fixed={false}> | ||||||
|  |       <div> | ||||||
|  |         <a href="https://coreui.io" target="_blank" rel="noopener noreferrer">CoreUI</a> | ||||||
|  |         <span className="ml-1">© 2020 creativeLabs.</span> | ||||||
|  |       </div> | ||||||
|  |       <div className="mfs-auto"> | ||||||
|  |         <span className="mr-1">Powered by</span> | ||||||
|  |         <a href="https://coreui.io/react" target="_blank" rel="noopener noreferrer">CoreUI for React</a> | ||||||
|  |       </div> | ||||||
|  |     </CFooter> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default React.memo(TheFooter) | ||||||
							
								
								
									
										78
									
								
								src/containers/TheHeader.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/containers/TheHeader.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import { useSelector, useDispatch } from 'react-redux' | ||||||
|  | import { logout } from '../utils/authHelper' | ||||||
|  | import { | ||||||
|  |   CHeader, | ||||||
|  |   CToggler, | ||||||
|  |   CHeaderBrand, | ||||||
|  |   CHeaderNav, | ||||||
|  |   CSubheader, | ||||||
|  |   CBreadcrumbRouter, | ||||||
|  |   CLink | ||||||
|  | } from '@coreui/react' | ||||||
|  | import CIcon from '@coreui/icons-react' | ||||||
|  | import { cilAccountLogout} from '@coreui/icons'; | ||||||
|  | import routes from '../routes' | ||||||
|  |  | ||||||
|  | const TheHeader = () => { | ||||||
|  |   const dispatch = useDispatch() | ||||||
|  |   const sidebarShow = useSelector(state => state.sidebarShow) | ||||||
|  |  | ||||||
|  |   const toggleSidebar = () => { | ||||||
|  |     const val = [true, 'responsive'].includes(sidebarShow) ? false : 'responsive' | ||||||
|  |     dispatch({type: 'set', sidebarShow: val}) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const toggleSidebarMobile = () => { | ||||||
|  |     const val = [false, 'responsive'].includes(sidebarShow) ? true : 'responsive' | ||||||
|  |     dispatch({type: 'set', sidebarShow: val}) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <CHeader withSubheader> | ||||||
|  |     <CToggler | ||||||
|  |       inHeader | ||||||
|  |       className="ml-md-3 d-lg-none" | ||||||
|  |       onClick={toggleSidebarMobile} | ||||||
|  |     /> | ||||||
|  |     <CToggler | ||||||
|  |       inHeader | ||||||
|  |       className="ml-3 d-md-down-none" | ||||||
|  |       onClick={toggleSidebar} | ||||||
|  |     /> | ||||||
|  |       <CHeaderBrand className="mx-auto d-lg-none" to="/"> | ||||||
|  |         <CIcon name="logo" height="48" alt="Logo"/> | ||||||
|  |       </CHeaderBrand> | ||||||
|  |  | ||||||
|  |       <CHeaderNav className="d-md-down-none mr-auto"> | ||||||
|  |       </CHeaderNav> | ||||||
|  |  | ||||||
|  |       <CHeaderNav className="px-3"> | ||||||
|  |         <CLink className="c-subheader-nav-link"> | ||||||
|  |         <CIcon name="cilAccountLogout" content={cilAccountLogout} size="2xl" onClick={() => { logout();}} /> | ||||||
|  |         </CLink> | ||||||
|  |       </CHeaderNav> | ||||||
|  |  | ||||||
|  |       <CSubheader className="px-3 justify-content-between"> | ||||||
|  |         <CBreadcrumbRouter  | ||||||
|  |           className="border-0 c-subheader-nav m-0 px-0 px-md-3"  | ||||||
|  |           routes={routes} | ||||||
|  |         /> | ||||||
|  |           <div className="d-md-down-none mfe-2 c-subheader-nav"> | ||||||
|  |             <CLink  | ||||||
|  |               className="c-subheader-nav-link"  | ||||||
|  |               aria-current="page"  | ||||||
|  |               to="/devices" | ||||||
|  |             > | ||||||
|  |               <CIcon name="cil-graph" alt="Dashboard" /> Dashboard | ||||||
|  |             </CLink> | ||||||
|  |             <CLink className="c-subheader-nav-link" href="#"> | ||||||
|  |               <CIcon name="cil-settings" alt="Settings" /> Settings | ||||||
|  |             </CLink> | ||||||
|  |           </div> | ||||||
|  |       </CSubheader> | ||||||
|  |     </CHeader> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default TheHeader | ||||||
							
								
								
									
										33
									
								
								src/containers/TheLayout.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/containers/TheLayout.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import { | ||||||
|  |   TheContent, | ||||||
|  |   TheSidebar, | ||||||
|  |   TheFooter, | ||||||
|  |   TheHeader | ||||||
|  | } from './index'; | ||||||
|  | import { useSelector } from 'react-redux'; | ||||||
|  |  | ||||||
|  | const TheLayout = (props) => { | ||||||
|  |   const { isLoggedIn } = useSelector(state => state.connected); | ||||||
|  |   if(isLoggedIn){ | ||||||
|  |     return ( | ||||||
|  |         <div> | ||||||
|  |             {props.children} | ||||||
|  |         </div> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |   return ( | ||||||
|  |     <div className="c-app c-default-layout"> | ||||||
|  |       <TheSidebar/> | ||||||
|  |       <div className="c-wrapper"> | ||||||
|  |         <TheHeader/> | ||||||
|  |         <div className="c-body"> | ||||||
|  |           <TheContent/> | ||||||
|  |         </div> | ||||||
|  |         <TheFooter/> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default TheLayout | ||||||
							
								
								
									
										58
									
								
								src/containers/TheSidebar.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/containers/TheSidebar.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import { useSelector, useDispatch } from 'react-redux' | ||||||
|  | import { | ||||||
|  |   CCreateElement, | ||||||
|  |   CSidebar, | ||||||
|  |   CSidebarBrand, | ||||||
|  |   CSidebarNav, | ||||||
|  |   CSidebarNavDivider, | ||||||
|  |   CSidebarNavTitle, | ||||||
|  |   CSidebarMinimizer, | ||||||
|  |   CSidebarNavDropdown, | ||||||
|  |   CSidebarNavItem, | ||||||
|  | } from '@coreui/react' | ||||||
|  |  | ||||||
|  | import CIcon from '@coreui/icons-react' | ||||||
|  |  | ||||||
|  | // sidebar nav config | ||||||
|  | import navigation from './_nav' | ||||||
|  |  | ||||||
|  | const TheSidebar = () => { | ||||||
|  |   const dispatch = useDispatch() | ||||||
|  |   const show = useSelector(state => state.sidebarShow) | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <CSidebar | ||||||
|  |       show={show} | ||||||
|  |       onShowChange={(val) => dispatch({type: 'set', sidebarShow: val })} | ||||||
|  |     > | ||||||
|  |       <CSidebarBrand className="d-md-down-none" to="/devices"> | ||||||
|  |         <CIcon | ||||||
|  |           className="c-sidebar-brand-full" | ||||||
|  |           name="logo-negative" | ||||||
|  |           height={35} | ||||||
|  |         /> | ||||||
|  |         <CIcon | ||||||
|  |           className="c-sidebar-brand-minimized" | ||||||
|  |           name="sygnet" | ||||||
|  |           height={35} | ||||||
|  |         /> | ||||||
|  |       </CSidebarBrand> | ||||||
|  |       <CSidebarNav> | ||||||
|  |  | ||||||
|  |         <CCreateElement | ||||||
|  |           items={navigation} | ||||||
|  |           components={{ | ||||||
|  |             CSidebarNavDivider, | ||||||
|  |             CSidebarNavDropdown, | ||||||
|  |             CSidebarNavItem, | ||||||
|  |             CSidebarNavTitle | ||||||
|  |           }} | ||||||
|  |         /> | ||||||
|  |       </CSidebarNav> | ||||||
|  |       <CSidebarMinimizer className="c-d-md-down-none"/> | ||||||
|  |     </CSidebar> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default React.memo(TheSidebar) | ||||||
							
								
								
									
										22
									
								
								src/containers/_nav.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/containers/_nav.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | const _nav =  [ | ||||||
|  |   { | ||||||
|  |     _tag: 'CSidebarNavItem', | ||||||
|  |     name: 'List of Devices', | ||||||
|  |     to: '/devices', | ||||||
|  |     icon: 'cilNotes' | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     _tag: 'CSidebarNavItem', | ||||||
|  |     name: 'Create Device', | ||||||
|  |     to: '/Create', | ||||||
|  |     icon: 'cilPencil', | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     _tag: 'CSidebarNavItem', | ||||||
|  |     name: 'Settings', | ||||||
|  |     to: '/Settings', | ||||||
|  |     icon: 'cil-settings', | ||||||
|  |   }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | export default _nav | ||||||
							
								
								
									
										13
									
								
								src/containers/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/containers/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import TheContent from './TheContent' | ||||||
|  | import TheFooter from './TheFooter' | ||||||
|  | import TheHeader from './TheHeader' | ||||||
|  | import TheLayout from './TheLayout' | ||||||
|  | import TheSidebar from './TheSidebar' | ||||||
|  |  | ||||||
|  | export { | ||||||
|  |   TheContent, | ||||||
|  |   TheFooter, | ||||||
|  |   TheHeader, | ||||||
|  |   TheLayout, | ||||||
|  |   TheSidebar | ||||||
|  | } | ||||||
| @@ -1,67 +0,0 @@ | |||||||
| import React, { useState } from 'react'; |  | ||||||
| import { useSelector, useDispatch } from 'react-redux'; |  | ||||||
| import { |  | ||||||
|   decrement, |  | ||||||
|   increment, |  | ||||||
|   incrementByAmount, |  | ||||||
|   incrementAsync, |  | ||||||
|   incrementIfOdd, |  | ||||||
|   selectCount, |  | ||||||
| } from './counterSlice'; |  | ||||||
| import styles from './Counter.module.css'; |  | ||||||
|  |  | ||||||
| export function Counter() { |  | ||||||
|   const count = useSelector(selectCount); |  | ||||||
|   const dispatch = useDispatch(); |  | ||||||
|   const [incrementAmount, setIncrementAmount] = useState('2'); |  | ||||||
|  |  | ||||||
|   const incrementValue = Number(incrementAmount) || 0; |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <div> |  | ||||||
|       <div className={styles.row}> |  | ||||||
|         <button |  | ||||||
|           className={styles.button} |  | ||||||
|           aria-label="Decrement value" |  | ||||||
|           onClick={() => dispatch(decrement())} |  | ||||||
|         > |  | ||||||
|           - |  | ||||||
|         </button> |  | ||||||
|         <span className={styles.value}>{count}</span> |  | ||||||
|         <button |  | ||||||
|           className={styles.button} |  | ||||||
|           aria-label="Increment value" |  | ||||||
|           onClick={() => dispatch(increment())} |  | ||||||
|         > |  | ||||||
|           + |  | ||||||
|         </button> |  | ||||||
|       </div> |  | ||||||
|       <div className={styles.row}> |  | ||||||
|         <input |  | ||||||
|           className={styles.textbox} |  | ||||||
|           aria-label="Set increment amount" |  | ||||||
|           value={incrementAmount} |  | ||||||
|           onChange={(e) => setIncrementAmount(e.target.value)} |  | ||||||
|         /> |  | ||||||
|         <button |  | ||||||
|           className={styles.button} |  | ||||||
|           onClick={() => dispatch(incrementByAmount(incrementValue))} |  | ||||||
|         > |  | ||||||
|           Add Amount |  | ||||||
|         </button> |  | ||||||
|         <button |  | ||||||
|           className={styles.asyncButton} |  | ||||||
|           onClick={() => dispatch(incrementAsync(incrementValue))} |  | ||||||
|         > |  | ||||||
|           Add Async |  | ||||||
|         </button> |  | ||||||
|         <button |  | ||||||
|           className={styles.button} |  | ||||||
|           onClick={() => dispatch(incrementIfOdd(incrementValue))} |  | ||||||
|         > |  | ||||||
|           Add If Odd |  | ||||||
|         </button> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
| @@ -1,78 +0,0 @@ | |||||||
| .row { |  | ||||||
|   display: flex; |  | ||||||
|   align-items: center; |  | ||||||
|   justify-content: center; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .row > button { |  | ||||||
|   margin-left: 4px; |  | ||||||
|   margin-right: 8px; |  | ||||||
| } |  | ||||||
| .row:not(:last-child) { |  | ||||||
|   margin-bottom: 16px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .value { |  | ||||||
|   font-size: 78px; |  | ||||||
|   padding-left: 16px; |  | ||||||
|   padding-right: 16px; |  | ||||||
|   margin-top: 2px; |  | ||||||
|   font-family: 'Courier New', Courier, monospace; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .button { |  | ||||||
|   appearance: none; |  | ||||||
|   background: none; |  | ||||||
|   font-size: 32px; |  | ||||||
|   padding-left: 12px; |  | ||||||
|   padding-right: 12px; |  | ||||||
|   outline: none; |  | ||||||
|   border: 2px solid transparent; |  | ||||||
|   color: rgb(112, 76, 182); |  | ||||||
|   padding-bottom: 4px; |  | ||||||
|   cursor: pointer; |  | ||||||
|   background-color: rgba(112, 76, 182, 0.1); |  | ||||||
|   border-radius: 2px; |  | ||||||
|   transition: all 0.15s; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .textbox { |  | ||||||
|   font-size: 32px; |  | ||||||
|   padding: 2px; |  | ||||||
|   width: 64px; |  | ||||||
|   text-align: center; |  | ||||||
|   margin-right: 4px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .button:hover, |  | ||||||
| .button:focus { |  | ||||||
|   border: 2px solid rgba(112, 76, 182, 0.4); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .button:active { |  | ||||||
|   background-color: rgba(112, 76, 182, 0.2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .asyncButton { |  | ||||||
|   composes: button; |  | ||||||
|   position: relative; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .asyncButton:after { |  | ||||||
|   content: ''; |  | ||||||
|   background-color: rgba(112, 76, 182, 0.15); |  | ||||||
|   display: block; |  | ||||||
|   position: absolute; |  | ||||||
|   width: 100%; |  | ||||||
|   height: 100%; |  | ||||||
|   left: 0; |  | ||||||
|   top: 0; |  | ||||||
|   opacity: 0; |  | ||||||
|   transition: width 1s linear, opacity 0.5s ease 1s; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .asyncButton:active:after { |  | ||||||
|   width: 0%; |  | ||||||
|   opacity: 1; |  | ||||||
|   transition: 0s; |  | ||||||
| } |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| // A mock function to mimic making an async request for data |  | ||||||
| export function fetchCount(amount = 1) { |  | ||||||
|   return new Promise((resolve) => |  | ||||||
|     setTimeout(() => resolve({ data: amount }), 500) |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; |  | ||||||
| import { fetchCount } from './counterAPI'; |  | ||||||
|  |  | ||||||
| const initialState = { |  | ||||||
|   value: 0, |  | ||||||
|   status: 'idle', |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| // The function below is called a thunk and allows us to perform async logic. It |  | ||||||
| // can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This |  | ||||||
| // will call the thunk with the `dispatch` function as the first argument. Async |  | ||||||
| // code can then be executed and other actions can be dispatched. Thunks are |  | ||||||
| // typically used to make async requests. |  | ||||||
| export const incrementAsync = createAsyncThunk( |  | ||||||
|   'counter/fetchCount', |  | ||||||
|   async (amount) => { |  | ||||||
|     const response = await fetchCount(amount); |  | ||||||
|     // The value we return becomes the `fulfilled` action payload |  | ||||||
|     return response.data; |  | ||||||
|   } |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| export const counterSlice = createSlice({ |  | ||||||
|   name: 'counter', |  | ||||||
|   initialState, |  | ||||||
|   // The `reducers` field lets us define reducers and generate associated actions |  | ||||||
|   reducers: { |  | ||||||
|     increment: (state) => { |  | ||||||
|       // Redux Toolkit allows us to write "mutating" logic in reducers. It |  | ||||||
|       // doesn't actually mutate the state because it uses the Immer library, |  | ||||||
|       // which detects changes to a "draft state" and produces a brand new |  | ||||||
|       // immutable state based off those changes |  | ||||||
|       state.value += 1; |  | ||||||
|     }, |  | ||||||
|     decrement: (state) => { |  | ||||||
|       state.value -= 1; |  | ||||||
|     }, |  | ||||||
|     // Use the PayloadAction type to declare the contents of `action.payload` |  | ||||||
|     incrementByAmount: (state, action) => { |  | ||||||
|       state.value += action.payload; |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
|   // The `extraReducers` field lets the slice handle actions defined elsewhere, |  | ||||||
|   // including actions generated by createAsyncThunk or in other slices. |  | ||||||
|   extraReducers: (builder) => { |  | ||||||
|     builder |  | ||||||
|       .addCase(incrementAsync.pending, (state) => { |  | ||||||
|         state.status = 'loading'; |  | ||||||
|       }) |  | ||||||
|       .addCase(incrementAsync.fulfilled, (state, action) => { |  | ||||||
|         state.status = 'idle'; |  | ||||||
|         state.value += action.payload; |  | ||||||
|       }); |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| export const { increment, decrement, incrementByAmount } = counterSlice.actions; |  | ||||||
|  |  | ||||||
| // The function below is called a selector and allows us to select a value from |  | ||||||
| // the state. Selectors can also be defined inline where they're used instead of |  | ||||||
| // in the slice file. For example: `useSelector((state: RootState) => state.counter.value)` |  | ||||||
| export const selectCount = (state) => state.counter.value; |  | ||||||
|  |  | ||||||
| // We can also write thunks by hand, which may contain both sync and async logic. |  | ||||||
| // Here's an example of conditionally dispatching actions based on current state. |  | ||||||
| export const incrementIfOdd = (amount) => (dispatch, getState) => { |  | ||||||
|   const currentValue = selectCount(getState()); |  | ||||||
|   if (currentValue % 2 === 1) { |  | ||||||
|     dispatch(incrementByAmount(amount)); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export default counterSlice.reducer; |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| import counterReducer, { |  | ||||||
|   increment, |  | ||||||
|   decrement, |  | ||||||
|   incrementByAmount, |  | ||||||
| } from './counterSlice'; |  | ||||||
|  |  | ||||||
| describe('counter reducer', () => { |  | ||||||
|   const initialState = { |  | ||||||
|     value: 3, |  | ||||||
|     status: 'idle', |  | ||||||
|   }; |  | ||||||
|   it('should handle initial state', () => { |  | ||||||
|     expect(counterReducer(undefined, { type: 'unknown' })).toEqual({ |  | ||||||
|       value: 0, |  | ||||||
|       status: 'idle', |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   it('should handle increment', () => { |  | ||||||
|     const actual = counterReducer(initialState, increment()); |  | ||||||
|     expect(actual.value).toEqual(4); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   it('should handle decrement', () => { |  | ||||||
|     const actual = counterReducer(initialState, decrement()); |  | ||||||
|     expect(actual.value).toEqual(2); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   it('should handle incrementByAmount', () => { |  | ||||||
|     const actual = counterReducer(initialState, incrementByAmount(2)); |  | ||||||
|     expect(actual.value).toEqual(5); |  | ||||||
|   }); |  | ||||||
| }); |  | ||||||
							
								
								
									
										16
									
								
								src/index.js
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/index.js
									
									
									
									
									
								
							| @@ -1,21 +1,19 @@ | |||||||
| import React from 'react'; | import React from 'react'; | ||||||
| import ReactDOM from 'react-dom'; | import ReactDOM from 'react-dom'; | ||||||
| import './index.css'; | import './index.css'; | ||||||
| import App from './App'; | import App from './App.js'; | ||||||
| import { store } from './app/store'; | import store from './store'; | ||||||
| import { Provider } from 'react-redux'; | import { Provider } from 'react-redux'; | ||||||
| import * as serviceWorker from './serviceWorker'; | import 'bootstrap/dist/css/bootstrap.min.css' | ||||||
|  | import { icons } from './assets/icons' | ||||||
|  |  | ||||||
|  | React.icons = icons; | ||||||
|  |  | ||||||
| ReactDOM.render( | ReactDOM.render( | ||||||
|   <React.StrictMode> |   <React.StrictMode> | ||||||
|     <Provider store={store}> |     <Provider store={store}> | ||||||
|       <App /> |       <App/> | ||||||
|     </Provider> |     </Provider> | ||||||
|   </React.StrictMode>, |   </React.StrictMode>, | ||||||
|   document.getElementById('root') |   document.getElementById('root') | ||||||
| ); | ); | ||||||
|  |  | ||||||
| // If you want your app to work offline and load faster, you can change |  | ||||||
| // unregister() to register() below. Note this comes with some pitfalls. |  | ||||||
| // Learn more about service workers: https://bit.ly/CRA-PWA |  | ||||||
| serviceWorker.unregister(); |  | ||||||
|   | |||||||
| @@ -1 +0,0 @@ | |||||||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><g fill="#764ABC"><path d="M65.6 65.4c2.9-.3 5.1-2.8 5-5.8-.1-3-2.6-5.4-5.6-5.4h-.2c-3.1.1-5.5 2.7-5.4 5.8.1 1.5.7 2.8 1.6 3.7-3.4 6.7-8.6 11.6-16.4 15.7-5.3 2.8-10.8 3.8-16.3 3.1-4.5-.6-8-2.6-10.2-5.9-3.2-4.9-3.5-10.2-.8-15.5 1.9-3.8 4.9-6.6 6.8-8-.4-1.3-1-3.5-1.3-5.1-14.5 10.5-13 24.7-8.6 31.4 3.3 5 10 8.1 17.4 8.1 2 0 4-.2 6-.7 12.8-2.5 22.5-10.1 28-21.4z"/><path d="M83.2 53c-7.6-8.9-18.8-13.8-31.6-13.8H50c-.9-1.8-2.8-3-4.9-3h-.2c-3.1.1-5.5 2.7-5.4 5.8.1 3 2.6 5.4 5.6 5.4h.2c2.2-.1 4.1-1.5 4.9-3.4H52c7.6 0 14.8 2.2 21.3 6.5 5 3.3 8.6 7.6 10.6 12.8 1.7 4.2 1.6 8.3-.2 11.8-2.8 5.3-7.5 8.2-13.7 8.2-4 0-7.8-1.2-9.8-2.1-1.1 1-3.1 2.6-4.5 3.6 4.3 2 8.7 3.1 12.9 3.1 9.6 0 16.7-5.3 19.4-10.6 2.9-5.8 2.7-15.8-4.8-24.3z"/><path d="M32.4 67.1c.1 3 2.6 5.4 5.6 5.4h.2c3.1-.1 5.5-2.7 5.4-5.8-.1-3-2.6-5.4-5.6-5.4h-.2c-.2 0-.5 0-.7.1-4.1-6.8-5.8-14.2-5.2-22.2.4-6 2.4-11.2 5.9-15.5 2.9-3.7 8.5-5.5 12.3-5.6 10.6-.2 15.1 13 15.4 18.3 1.3.3 3.5 1 5 1.5-1.2-16.2-11.2-24.6-20.8-24.6-9 0-17.3 6.5-20.6 16.1-4.6 12.8-1.6 25.1 4 34.8-.5.7-.8 1.8-.7 2.9z"/></g></svg> |  | ||||||
| Before Width: | Height: | Size: 1.1 KiB | 
							
								
								
									
										13
									
								
								src/routes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/routes.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import React from 'react'; | ||||||
|  |  | ||||||
|  | const DevicePage = React.lazy(() => import('./views/pages/DevicePage')); | ||||||
|  | const DeviceListPage = React.lazy(() => import('./views/pages/DeviceListPage')); | ||||||
|  |  | ||||||
|  | const routes = [ | ||||||
|  |     { path: '/devices', exact: true, name: 'Devices', component: DeviceListPage }, | ||||||
|  |     { path: '/devices/:deviceId', name: 'Device Page', component: DevicePage }, | ||||||
|  |     { path: '/Device', name: 'Device', component: DevicePage }, | ||||||
|  |     { path: '/page2', name: 'Page2', component: DeviceListPage, exact: true }, | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  |   export default routes; | ||||||
							
								
								
									
										1
									
								
								src/scss/_custom.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/scss/_custom.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | // Here you can add other styles | ||||||
							
								
								
									
										16
									
								
								src/scss/_fixes.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/scss/_fixes.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | // todo: disabled button styles | ||||||
|  | button { | ||||||
|  |   &:disabled { | ||||||
|  |     cursor: default; | ||||||
|  |   } | ||||||
|  |   &.disabled { | ||||||
|  |     cursor: default; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // todo: brand button icon margin | ||||||
|  | .btn-brand:not(:only-child) { | ||||||
|  |   .c-icon { | ||||||
|  |     margin-top: 0 !important; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								src/scss/_variables.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/scss/_variables.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | // Variable overrides | ||||||
							
								
								
									
										11
									
								
								src/scss/style.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/scss/style.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | // If you want to override variables do it here | ||||||
|  | @import "variables"; | ||||||
|  |  | ||||||
|  | // Import CoreUI styles | ||||||
|  | @import "~@coreui/coreui/scss/coreui.scss"; | ||||||
|  |  | ||||||
|  | // Some temp fixes | ||||||
|  | @import "fixes"; | ||||||
|  |  | ||||||
|  | // If you want to add something do it here | ||||||
|  | @import "custom"; | ||||||
							
								
								
									
										20
									
								
								src/store.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/store.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | import { createStore } from 'redux' | ||||||
|  |  | ||||||
|  | const initialState = { | ||||||
|  |   sidebarShow: 'responsive', | ||||||
|  |   connected: false, | ||||||
|  |   selectedDeviceId: null, | ||||||
|  |   selectedDevice: null | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const changeState = (state = initialState, { type, ...rest }) => { | ||||||
|  |   switch (type) { | ||||||
|  |     case 'set': | ||||||
|  |       return {...state, ...rest } | ||||||
|  |     default: | ||||||
|  |       return state | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const store = createStore(changeState) | ||||||
|  | export default store | ||||||
							
								
								
									
										13
									
								
								src/utils/authHelper.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/utils/authHelper.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | export const logout = () => { | ||||||
|  |     sessionStorage.clear(); | ||||||
|  |     window.location.replace('/'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getToken = () => { | ||||||
|  |     const token = sessionStorage.getItem('access_token'); | ||||||
|  |     if (token === undefined || token === null) { | ||||||
|  |         logout(); | ||||||
|  |         return; | ||||||
|  |     }  | ||||||
|  |     return token; | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								src/utils/axiosInstance.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/utils/axiosInstance.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | import * as axios from 'axios'; | ||||||
|  | import axiosRetry from 'axios-retry'; | ||||||
|  |  | ||||||
|  | const axiosInstance = axios.create({ | ||||||
|  |     baseURL: `${process.env.REACT_APP_BASE_URL}` | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | axiosRetry(axiosInstance , { | ||||||
|  |     retries: 3, | ||||||
|  |     retryDelay: (retryCount) => { | ||||||
|  |         console.log(`retry attempt: ${retryCount}`); | ||||||
|  |         return axiosRetry.exponentialDelay; | ||||||
|  |     }, | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | axiosInstance.defaults.headers.get['Accept'] = 'application/json'   // default header for all get request | ||||||
|  | axiosInstance.defaults.headers.post['Accept'] = 'application/json'  // default header for all POST request | ||||||
|  |  | ||||||
|  | axiosInstance.interceptors.response.use( | ||||||
|  |     //Success actions | ||||||
|  |     undefined,  | ||||||
|  |     function(error) { | ||||||
|  |         console.log(error); | ||||||
|  |         switch(error.response.status){ | ||||||
|  |             case 401: | ||||||
|  |                 console.log('Error 401 ' + error ); | ||||||
|  |                 break; | ||||||
|  |             case 403: | ||||||
|  |                 console.log('Error 403 ' + error ); | ||||||
|  |                 sessionStorage.clear(); | ||||||
|  |                 window.location.href = '/'; | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 console.log('Default ' + error.response.status); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |         return Promise.reject(error); | ||||||
|  |     } | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | export default axiosInstance; | ||||||
							
								
								
									
										3
									
								
								src/utils/helper.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/utils/helper.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | export const cleanTimestamp = (timestamp) => { | ||||||
|  |     return timestamp.replace('T', ' ').replace('Z', ' '); | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								src/views/icons/brands/Brands.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/views/icons/brands/Brands.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import { CCard, CCardBody, CCardHeader, CCol, CRow } from '@coreui/react' | ||||||
|  | import CIcon from '@coreui/icons-react' | ||||||
|  | import { brandSet } from '@coreui/icons' | ||||||
|  | import { DocsLink } from 'src/reusable' | ||||||
|  |  | ||||||
|  | const toKebabCase = (str) => { | ||||||
|  |   return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getIconsView = iconset => { | ||||||
|  |   return Object.entries(iconset).map(([name, value]) => ( | ||||||
|  |     <CCol className="mb-5" xs="6" sm="4" md="3" xl="2" key={name}> | ||||||
|  |       <CIcon content={value} size="2xl"/> | ||||||
|  |       <div>{toKebabCase(name)}</div> | ||||||
|  |     </CCol> | ||||||
|  |   )) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const CoreUIIcons = () => { | ||||||
|  |   return ( | ||||||
|  |     <CCard> | ||||||
|  |       <CCardHeader> | ||||||
|  |         Brand Icons | ||||||
|  |         <DocsLink href="https://github.com/coreui/coreui-icons" text="GitHub"/> | ||||||
|  |       </CCardHeader> | ||||||
|  |       <CCardBody> | ||||||
|  |         <CRow className="text-center"> | ||||||
|  |           {getIconsView(brandSet)} | ||||||
|  |         </CRow> | ||||||
|  |       </CCardBody> | ||||||
|  |     </CCard> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default CoreUIIcons | ||||||
							
								
								
									
										23
									
								
								src/views/icons/coreui-icons/CoreUIIcons.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/views/icons/coreui-icons/CoreUIIcons.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import { CCard, CCardBody, CCardHeader, CRow } from '@coreui/react' | ||||||
|  | import { freeSet } from '@coreui/icons' | ||||||
|  | import { getIconsView } from '../brands/Brands.js' | ||||||
|  | import { DocsLink } from 'src/reusable' | ||||||
|  |  | ||||||
|  | const CoreUIIcons = () => { | ||||||
|  |   return ( | ||||||
|  |     <CCard> | ||||||
|  |       <CCardHeader> | ||||||
|  |         Free Icons / as CIcon{' '} | ||||||
|  |         <DocsLink href="https://github.com/coreui/coreui-icons" text="GitHub"/> | ||||||
|  |       </CCardHeader> | ||||||
|  |       <CCardBody> | ||||||
|  |         <CRow className="text-center"> | ||||||
|  |           {getIconsView(freeSet)} | ||||||
|  |         </CRow> | ||||||
|  |       </CCardBody> | ||||||
|  |     </CCard> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default CoreUIIcons | ||||||
							
								
								
									
										23
									
								
								src/views/icons/flags/Flags.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/views/icons/flags/Flags.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import { CCard, CCardBody, CCardHeader, CRow } from '@coreui/react' | ||||||
|  | import { getIconsView } from '../brands/Brands.js' | ||||||
|  | import { flagSet } from '@coreui/icons' | ||||||
|  | import { DocsLink } from 'src/reusable' | ||||||
|  |  | ||||||
|  | const CoreUIIcons = () => { | ||||||
|  |   return ( | ||||||
|  |     <CCard> | ||||||
|  |       <CCardHeader> | ||||||
|  |         Flag Icons | ||||||
|  |         <DocsLink href="https://github.com/coreui/coreui-icons" text="GitHub"/> | ||||||
|  |       </CCardHeader> | ||||||
|  |       <CCardBody> | ||||||
|  |         <CRow className="text-center"> | ||||||
|  |           {getIconsView(flagSet)} | ||||||
|  |         </CRow> | ||||||
|  |       </CCardBody> | ||||||
|  |     </CCard> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default CoreUIIcons | ||||||
							
								
								
									
										7
									
								
								src/views/icons/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/views/icons/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | import CoreUIIcons from './coreui-icons'; | ||||||
|  | import Flags from './flags'; | ||||||
|  | import Brands from './brands'; | ||||||
|  |  | ||||||
|  | export { | ||||||
|  |   CoreUIIcons, Flags, Brands | ||||||
|  | }; | ||||||
							
								
								
									
										12
									
								
								src/views/pages/DeviceListPage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/views/pages/DeviceListPage.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | import React from 'react'; | ||||||
|  | import DeviceList from '../../components/DeviceList'; | ||||||
|  |  | ||||||
|  | const DeviceListPage = (props) => { | ||||||
|  |     return ( | ||||||
|  |         <div className="App"> | ||||||
|  |             <DeviceList /> | ||||||
|  |         </div> | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default DeviceListPage; | ||||||
							
								
								
									
										124
									
								
								src/views/pages/DevicePage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/views/pages/DevicePage.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | |||||||
|  | import React, { useEffect, useState, useCallback } from 'react' | ||||||
|  | import { useDispatch, useSelector } from 'react-redux'; | ||||||
|  | import { useParams } from 'react-router-dom'; | ||||||
|  | import { | ||||||
|  |     CRow, | ||||||
|  |     CCol, | ||||||
|  |     CButton, | ||||||
|  |   } from '@coreui/react' | ||||||
|  | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||||
|  | import { faSync } from '@fortawesome/free-solid-svg-icons'; | ||||||
|  | import axiosInstance from '../../utils/axiosInstance'; | ||||||
|  | import { getToken } from '../../utils/authHelper'; | ||||||
|  |  | ||||||
|  | import DeviceHealth from '../../components/DeviceHealth'; | ||||||
|  | import DeviceConfiguration from '../../components/DeviceConfiguration'; | ||||||
|  | import DeviceActions from '../../components/DeviceActions' | ||||||
|  |  | ||||||
|  | const DevicePage = (props) => { | ||||||
|  |     const dispatch = useDispatch(); | ||||||
|  |     const [device, setDevice] = useState([]); | ||||||
|  |     const [lastRefresh, setLastRefresh] = useState([]); | ||||||
|  |  | ||||||
|  |     //Storing the deviceId in the store | ||||||
|  |     let selectedDeviceId = useSelector(state => state.selectedDeviceId); | ||||||
|  |     let { deviceId } = useParams(); | ||||||
|  |  | ||||||
|  |     if(!selectedDeviceId || selectedDeviceId !== deviceId){ | ||||||
|  |         dispatch({type: 'set', selectedDeviceId: deviceId}); | ||||||
|  |         selectedDeviceId = deviceId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const refreshDevice = useCallback(() => { | ||||||
|  |         const addStatusToDevice = (device, options) => { | ||||||
|  |             axiosInstance.get(`/device/${device.serialNumber}/status`, options) | ||||||
|  |             .then((response) => { | ||||||
|  |                 device = {...device, ...response.data}; | ||||||
|  |                 device.ipAddress = device.ipAddress.substr(0, device.ipAddress.indexOf(':')); | ||||||
|  |             }) | ||||||
|  |             .catch(error => { | ||||||
|  |                 console.log(error.response); | ||||||
|  |             }) | ||||||
|  |             .finally (() => { | ||||||
|  |                 addHealthChecksToDevice(device, options); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const addHealthChecksToDevice = (device, options) => { | ||||||
|  |             axiosInstance.get(`/device/${device.serialNumber}/healthchecks`, options) | ||||||
|  |             .then((response) => { | ||||||
|  |                 device.healthChecks = response.data.values; | ||||||
|  |             }) | ||||||
|  |             .catch(error => { | ||||||
|  |                 console.log(error); | ||||||
|  |                 console.log(error.response); | ||||||
|  |             }) | ||||||
|  |             .finally(() => { | ||||||
|  |                 setDevice(device); | ||||||
|  |                 dispatch({type: 'set', selectedDevice: device}); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const options = { | ||||||
|  |             headers : { | ||||||
|  |                 'Accept': 'application/json', | ||||||
|  |                 'Authorization': `Bearer ${getToken()}` | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         axiosInstance.get(`/device/${selectedDeviceId}`, options) | ||||||
|  |         .then((response) => { | ||||||
|  |           const date = new Date(); | ||||||
|  |           const dateAsString = date.toLocaleString(); | ||||||
|  |           setLastRefresh(dateAsString); | ||||||
|  |           addStatusToDevice(response.data, options); | ||||||
|  |         }) | ||||||
|  |         .catch(error => { | ||||||
|  |           console.log(error.response); | ||||||
|  |         }); | ||||||
|  |       }, [selectedDeviceId, dispatch]); | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |     useEffect(() => {refreshDevice();},[refreshDevice]); | ||||||
|  |  | ||||||
|  |     return ( | ||||||
|  |         <DeviceDisplay  | ||||||
|  |           device={device}  | ||||||
|  |           refresh={refreshDevice}  | ||||||
|  |           lastRefresh={lastRefresh} | ||||||
|  |         /> | ||||||
|  |       ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const DeviceDisplay = ({ device, refresh, lastRefresh }) => { | ||||||
|  |     return ( | ||||||
|  |         <> | ||||||
|  |         <div className="App"> | ||||||
|  |             <CRow> | ||||||
|  |                 <CCol xs='12' sm='6'> | ||||||
|  |                     <CButton onClick={ refresh }> | ||||||
|  |                         <FontAwesomeIcon icon={faSync} color='#007bff' size="2x"/> | ||||||
|  |                     </CButton> | ||||||
|  |                 </CCol> | ||||||
|  |                 <CCol xs='12' sm='6'> | ||||||
|  |                     <div className='form-inline justify-content-sm-end'> | ||||||
|  |                         Last refresh : {lastRefresh} | ||||||
|  |                     </div> | ||||||
|  |                 </CCol> | ||||||
|  |             </CRow> | ||||||
|  |             <CRow> | ||||||
|  |                 <CCol xs='12' sm='6'> | ||||||
|  |                     <DeviceConfiguration/> | ||||||
|  |                 </CCol> | ||||||
|  |                 <CCol xs='12' sm='6'> | ||||||
|  |                     <DeviceHealth/> | ||||||
|  |                     <DeviceActions/> | ||||||
|  |                 </CCol > | ||||||
|  |             </CRow> | ||||||
|  |         </div> | ||||||
|  |         </> | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default DevicePage; | ||||||
							
								
								
									
										92
									
								
								src/views/pages/Login.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/views/pages/Login.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | |||||||
|  | import React, { useState } from 'react' | ||||||
|  | import { | ||||||
|  |   CButton, | ||||||
|  |   CCard, | ||||||
|  |   CCardBody, | ||||||
|  |   CCardGroup, | ||||||
|  |   CCol, | ||||||
|  |   CContainer, | ||||||
|  |   CForm, | ||||||
|  |   CInput, | ||||||
|  |   CInputGroup, | ||||||
|  |   CInputGroupPrepend, | ||||||
|  |   CInputGroupText, | ||||||
|  |   CRow | ||||||
|  | } from '@coreui/react' | ||||||
|  | import CIcon from '@coreui/icons-react' | ||||||
|  | import { cilUser, cilLockLocked} from '@coreui/icons'; | ||||||
|  | import { useDispatch } from 'react-redux'; | ||||||
|  | import axiosInstance from '../../utils/axiosInstance'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const Login = () => { | ||||||
|  |   const dispatch = useDispatch(); | ||||||
|  |   const [userId, setUsername] = useState(''); | ||||||
|  |   const [password, setPassword] = useState(''); | ||||||
|  |  | ||||||
|  |   const SignIn = (credentials) => { | ||||||
|  |     axiosInstance.post('/oauth2', credentials) | ||||||
|  |     .then((response) => { | ||||||
|  |         sessionStorage.setItem('access_token', response.data.access_token); | ||||||
|  |         dispatch({type: 'set', connected: true}); | ||||||
|  |     }) | ||||||
|  |     .catch(error => { | ||||||
|  |         console.log(error.response); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   const formValidation = () => { | ||||||
|  |       if (userId.trim() === '' || password.trim() === ''){ | ||||||
|  |           return false; | ||||||
|  |       } | ||||||
|  |       return true; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <div className="c-app c-default-layout flex-row align-items-center"> | ||||||
|  |       <CContainer> | ||||||
|  |         <CRow className="justify-content-center"> | ||||||
|  |           <CCol md="8"> | ||||||
|  |             <CCardGroup> | ||||||
|  |               <CCard className="p-4"> | ||||||
|  |                 <CCardBody> | ||||||
|  |                   <CForm> | ||||||
|  |                     <h1>Login</h1> | ||||||
|  |                     <p className="text-muted">Sign In to your account</p> | ||||||
|  |                     <CInputGroup className="mb-3"> | ||||||
|  |                       <CInputGroupPrepend> | ||||||
|  |                         <CInputGroupText> | ||||||
|  |                           <CIcon name="cilUser" content={cilUser}/> | ||||||
|  |                         </CInputGroupText> | ||||||
|  |                       </CInputGroupPrepend> | ||||||
|  |                       <CInput type="text" placeholder="Username" autoComplete="username" onChange={event => setUsername(event.target.value)}/> | ||||||
|  |                     </CInputGroup> | ||||||
|  |                     <CInputGroup className="mb-4"> | ||||||
|  |                       <CInputGroupPrepend> | ||||||
|  |                         <CInputGroupText> | ||||||
|  |                           <CIcon name="cilLockLocked" content={cilLockLocked}/> | ||||||
|  |                         </CInputGroupText> | ||||||
|  |                       </CInputGroupPrepend> | ||||||
|  |                       <CInput type="password" placeholder="Password" autoComplete="current-password" onChange={event => setPassword(event.target.value)} /> | ||||||
|  |                     </CInputGroup> | ||||||
|  |                     <CRow> | ||||||
|  |                       <CCol xs="6"> | ||||||
|  |                         <CButton color="primary" className="px-4" onClick={event => formValidation() ? SignIn({ userId, password }) : alert('bad')}>Login | ||||||
|  |                       </CButton> | ||||||
|  |                       </CCol> | ||||||
|  |                       <CCol xs="6" className="text-right"> | ||||||
|  |                         <CButton color="link" className="px-0">Forgot password?</CButton> | ||||||
|  |                       </CCol> | ||||||
|  |                     </CRow> | ||||||
|  |                   </CForm> | ||||||
|  |                 </CCardBody> | ||||||
|  |               </CCard> | ||||||
|  |             </CCardGroup> | ||||||
|  |           </CCol> | ||||||
|  |         </CRow> | ||||||
|  |       </CContainer> | ||||||
|  |     </div> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |    | ||||||
|  |   export default Login | ||||||
|  |    | ||||||
		Reference in New Issue
	
	Block a user
	 bourquecharles
					bourquecharles