mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui.git
				synced 2025-10-30 18:27:53 +00:00 
			
		
		
		
	Compare commits
	
		
			8 Commits
		
	
	
		
			v2.7.0-RC2
			...
			v2.6.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 2c62c7bc92 | ||
|   | 2befa3ce6f | ||
|   | 5a39deaa37 | ||
|   | abb8b2ba0f | ||
|   | a22f33dade | ||
|   | 1990498f86 | ||
|   | dc035572f0 | ||
|   | 5101e41565 | 
							
								
								
									
										8
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							| @@ -17,10 +17,4 @@ jobs: | |||||||
|     steps: |     steps: | ||||||
|       - run: | |       - run: | | ||||||
|           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') |           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') | ||||||
|  |           curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw-ui/$PR_BRANCH_TAG" | ||||||
|           if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then |  | ||||||
|             echo "PR branch is $PR_BRANCH_TAG, deleting Docker image" |  | ||||||
|             curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw-ui/$PR_BRANCH_TAG" |  | ||||||
|           else |  | ||||||
|             echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image" |  | ||||||
|           fi |  | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| FROM node:18.7.0-alpine3.15 AS build | FROM node:14-alpine3.11 AS build | ||||||
|  |  | ||||||
| COPY package.json package-lock.json / | COPY package.json package-lock.json / | ||||||
|  |  | ||||||
| @@ -8,7 +8,7 @@ COPY . . | |||||||
|  |  | ||||||
| RUN npm run build | RUN npm run build | ||||||
|  |  | ||||||
| FROM nginx:1.22.0-alpine AS runtime | FROM nginx:1.20.1-alpine AS runtime | ||||||
|  |  | ||||||
| COPY --from=build /build/ /usr/share/nginx/html/ | COPY --from=build /build/ /usr/share/nginx/html/ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ fullnameOverride: "" | |||||||
| images: | images: | ||||||
|   owgwui: |   owgwui: | ||||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw-ui |     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw-ui | ||||||
|     tag: v2.7.0-RC2 |     tag: v2.6.0 | ||||||
|     pullPolicy: Always |     pullPolicy: Always | ||||||
|  |  | ||||||
| services: | services: | ||||||
|   | |||||||
							
								
								
									
										347
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										347
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,12 +1,12 @@ | |||||||
| { | { | ||||||
|   "name": "ucentral-client", |   "name": "ucentral-client", | ||||||
|   "version": "2.7.0(8)", |   "version": "2.6.29", | ||||||
|   "lockfileVersion": 2, |   "lockfileVersion": 2, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "packages": { |   "packages": { | ||||||
|     "": { |     "": { | ||||||
|       "name": "ucentral-client", |       "name": "ucentral-client", | ||||||
|       "version": "2.7.0(8)", |       "version": "2.6.29", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@coreui/coreui": "^3.4.0", |         "@coreui/coreui": "^3.4.0", | ||||||
|         "@coreui/icons": "^2.0.1", |         "@coreui/icons": "^2.0.1", | ||||||
| @@ -2069,64 +2069,6 @@ | |||||||
|       "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", |       "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "node_modules/@jridgewell/gen-mapping": { |  | ||||||
|       "version": "0.3.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", |  | ||||||
|       "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", |  | ||||||
|       "dev": true, |  | ||||||
|       "dependencies": { |  | ||||||
|         "@jridgewell/set-array": "^1.0.1", |  | ||||||
|         "@jridgewell/sourcemap-codec": "^1.4.10", |  | ||||||
|         "@jridgewell/trace-mapping": "^0.3.9" |  | ||||||
|       }, |  | ||||||
|       "engines": { |  | ||||||
|         "node": ">=6.0.0" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "node_modules/@jridgewell/resolve-uri": { |  | ||||||
|       "version": "3.1.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", |  | ||||||
|       "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", |  | ||||||
|       "dev": true, |  | ||||||
|       "engines": { |  | ||||||
|         "node": ">=6.0.0" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "node_modules/@jridgewell/set-array": { |  | ||||||
|       "version": "1.1.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", |  | ||||||
|       "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", |  | ||||||
|       "dev": true, |  | ||||||
|       "engines": { |  | ||||||
|         "node": ">=6.0.0" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "node_modules/@jridgewell/source-map": { |  | ||||||
|       "version": "0.3.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", |  | ||||||
|       "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", |  | ||||||
|       "dev": true, |  | ||||||
|       "dependencies": { |  | ||||||
|         "@jridgewell/gen-mapping": "^0.3.0", |  | ||||||
|         "@jridgewell/trace-mapping": "^0.3.9" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "node_modules/@jridgewell/sourcemap-codec": { |  | ||||||
|       "version": "1.4.14", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", |  | ||||||
|       "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", |  | ||||||
|       "dev": true |  | ||||||
|     }, |  | ||||||
|     "node_modules/@jridgewell/trace-mapping": { |  | ||||||
|       "version": "0.3.14", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", |  | ||||||
|       "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", |  | ||||||
|       "dev": true, |  | ||||||
|       "dependencies": { |  | ||||||
|         "@jridgewell/resolve-uri": "^3.0.3", |  | ||||||
|         "@jridgewell/sourcemap-codec": "^1.4.10" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "node_modules/@nodelib/fs.scandir": { |     "node_modules/@nodelib/fs.scandir": { | ||||||
|       "version": "2.1.5", |       "version": "2.1.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", |       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | ||||||
| @@ -7378,6 +7320,60 @@ | |||||||
|         "node": ">=12" |         "node": ">=12" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/html-minifier-terser/node_modules/acorn": { | ||||||
|  |       "version": "8.7.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", | ||||||
|  |       "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", | ||||||
|  |       "dev": true, | ||||||
|  |       "optional": true, | ||||||
|  |       "peer": true, | ||||||
|  |       "bin": { | ||||||
|  |         "acorn": "bin/acorn" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=0.4.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/html-minifier-terser/node_modules/source-map": { | ||||||
|  |       "version": "0.7.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", | ||||||
|  |       "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", | ||||||
|  |       "dev": true, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/html-minifier-terser/node_modules/terser": { | ||||||
|  |       "version": "5.10.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", | ||||||
|  |       "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", | ||||||
|  |       "dev": true, | ||||||
|  |       "dependencies": { | ||||||
|  |         "commander": "^2.20.0", | ||||||
|  |         "source-map": "~0.7.2", | ||||||
|  |         "source-map-support": "~0.5.20" | ||||||
|  |       }, | ||||||
|  |       "bin": { | ||||||
|  |         "terser": "bin/terser" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=10" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "acorn": "^8.5.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependenciesMeta": { | ||||||
|  |         "acorn": { | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/html-minifier-terser/node_modules/terser/node_modules/commander": { | ||||||
|  |       "version": "2.20.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", | ||||||
|  |       "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", | ||||||
|  |       "dev": true | ||||||
|  |     }, | ||||||
|     "node_modules/html-parse-stringify": { |     "node_modules/html-parse-stringify": { | ||||||
|       "version": "3.0.1", |       "version": "3.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", |       "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", | ||||||
| @@ -9205,9 +9201,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/moment": { |     "node_modules/moment": { | ||||||
|       "version": "2.29.4", |       "version": "2.29.3", | ||||||
|       "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", |       "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz", | ||||||
|       "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", |       "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": "*" |         "node": "*" | ||||||
|       } |       } | ||||||
| @@ -13077,24 +13073,6 @@ | |||||||
|         "node": ">=6" |         "node": ">=6" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/terser": { |  | ||||||
|       "version": "5.14.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", |  | ||||||
|       "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", |  | ||||||
|       "dev": true, |  | ||||||
|       "dependencies": { |  | ||||||
|         "@jridgewell/source-map": "^0.3.2", |  | ||||||
|         "acorn": "^8.5.0", |  | ||||||
|         "commander": "^2.20.0", |  | ||||||
|         "source-map-support": "~0.5.20" |  | ||||||
|       }, |  | ||||||
|       "bin": { |  | ||||||
|         "terser": "bin/terser" |  | ||||||
|       }, |  | ||||||
|       "engines": { |  | ||||||
|         "node": ">=10" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "node_modules/terser-webpack-plugin": { |     "node_modules/terser-webpack-plugin": { | ||||||
|       "version": "5.3.0", |       "version": "5.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz", |       "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz", | ||||||
| @@ -13129,6 +13107,26 @@ | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/terser-webpack-plugin/node_modules/acorn": { | ||||||
|  |       "version": "8.7.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", | ||||||
|  |       "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", | ||||||
|  |       "dev": true, | ||||||
|  |       "optional": true, | ||||||
|  |       "peer": true, | ||||||
|  |       "bin": { | ||||||
|  |         "acorn": "bin/acorn" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=0.4.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/terser-webpack-plugin/node_modules/commander": { | ||||||
|  |       "version": "2.20.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", | ||||||
|  |       "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", | ||||||
|  |       "dev": true | ||||||
|  |     }, | ||||||
|     "node_modules/terser-webpack-plugin/node_modules/has-flag": { |     "node_modules/terser-webpack-plugin/node_modules/has-flag": { | ||||||
|       "version": "4.0.0", |       "version": "4.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", |       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", | ||||||
| @@ -13194,23 +13192,39 @@ | |||||||
|         "url": "https://github.com/chalk/supports-color?sponsor=1" |         "url": "https://github.com/chalk/supports-color?sponsor=1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/terser/node_modules/acorn": { |     "node_modules/terser-webpack-plugin/node_modules/terser": { | ||||||
|       "version": "8.8.0", |       "version": "5.10.0", | ||||||
|       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", |       "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", | ||||||
|       "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", |       "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|  |       "dependencies": { | ||||||
|  |         "commander": "^2.20.0", | ||||||
|  |         "source-map": "~0.7.2", | ||||||
|  |         "source-map-support": "~0.5.20" | ||||||
|  |       }, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "acorn": "bin/acorn" |         "terser": "bin/terser" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=0.4.0" |         "node": ">=10" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "acorn": "^8.5.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependenciesMeta": { | ||||||
|  |         "acorn": { | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/terser/node_modules/commander": { |     "node_modules/terser-webpack-plugin/node_modules/terser/node_modules/source-map": { | ||||||
|       "version": "2.20.3", |       "version": "0.7.3", | ||||||
|       "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", |       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", | ||||||
|       "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", |       "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", | ||||||
|       "dev": true |       "dev": true, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 8" | ||||||
|  |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/text-table": { |     "node_modules/text-table": { | ||||||
|       "version": "0.2.0", |       "version": "0.2.0", | ||||||
| @@ -16400,55 +16414,6 @@ | |||||||
|       "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", |       "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "@jridgewell/gen-mapping": { |  | ||||||
|       "version": "0.3.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", |  | ||||||
|       "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", |  | ||||||
|       "dev": true, |  | ||||||
|       "requires": { |  | ||||||
|         "@jridgewell/set-array": "^1.0.1", |  | ||||||
|         "@jridgewell/sourcemap-codec": "^1.4.10", |  | ||||||
|         "@jridgewell/trace-mapping": "^0.3.9" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "@jridgewell/resolve-uri": { |  | ||||||
|       "version": "3.1.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", |  | ||||||
|       "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", |  | ||||||
|       "dev": true |  | ||||||
|     }, |  | ||||||
|     "@jridgewell/set-array": { |  | ||||||
|       "version": "1.1.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", |  | ||||||
|       "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", |  | ||||||
|       "dev": true |  | ||||||
|     }, |  | ||||||
|     "@jridgewell/source-map": { |  | ||||||
|       "version": "0.3.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", |  | ||||||
|       "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", |  | ||||||
|       "dev": true, |  | ||||||
|       "requires": { |  | ||||||
|         "@jridgewell/gen-mapping": "^0.3.0", |  | ||||||
|         "@jridgewell/trace-mapping": "^0.3.9" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "@jridgewell/sourcemap-codec": { |  | ||||||
|       "version": "1.4.14", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", |  | ||||||
|       "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", |  | ||||||
|       "dev": true |  | ||||||
|     }, |  | ||||||
|     "@jridgewell/trace-mapping": { |  | ||||||
|       "version": "0.3.14", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", |  | ||||||
|       "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", |  | ||||||
|       "dev": true, |  | ||||||
|       "requires": { |  | ||||||
|         "@jridgewell/resolve-uri": "^3.0.3", |  | ||||||
|         "@jridgewell/sourcemap-codec": "^1.4.10" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "@nodelib/fs.scandir": { |     "@nodelib/fs.scandir": { | ||||||
|       "version": "2.1.5", |       "version": "2.1.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", |       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | ||||||
| @@ -20459,6 +20424,41 @@ | |||||||
|         "param-case": "^3.0.4", |         "param-case": "^3.0.4", | ||||||
|         "relateurl": "^0.2.7", |         "relateurl": "^0.2.7", | ||||||
|         "terser": "^5.10.0" |         "terser": "^5.10.0" | ||||||
|  |       }, | ||||||
|  |       "dependencies": { | ||||||
|  |         "acorn": { | ||||||
|  |           "version": "8.7.0", | ||||||
|  |           "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", | ||||||
|  |           "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", | ||||||
|  |           "dev": true, | ||||||
|  |           "optional": true, | ||||||
|  |           "peer": true | ||||||
|  |         }, | ||||||
|  |         "source-map": { | ||||||
|  |           "version": "0.7.3", | ||||||
|  |           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", | ||||||
|  |           "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", | ||||||
|  |           "dev": true | ||||||
|  |         }, | ||||||
|  |         "terser": { | ||||||
|  |           "version": "5.10.0", | ||||||
|  |           "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", | ||||||
|  |           "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", | ||||||
|  |           "dev": true, | ||||||
|  |           "requires": { | ||||||
|  |             "commander": "^2.20.0", | ||||||
|  |             "source-map": "~0.7.2", | ||||||
|  |             "source-map-support": "~0.5.20" | ||||||
|  |           }, | ||||||
|  |           "dependencies": { | ||||||
|  |             "commander": { | ||||||
|  |               "version": "2.20.3", | ||||||
|  |               "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", | ||||||
|  |               "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", | ||||||
|  |               "dev": true | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "html-parse-stringify": { |     "html-parse-stringify": { | ||||||
| @@ -21815,9 +21815,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "moment": { |     "moment": { | ||||||
|       "version": "2.29.4", |       "version": "2.29.3", | ||||||
|       "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", |       "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz", | ||||||
|       "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" |       "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==" | ||||||
|     }, |     }, | ||||||
|     "mrmime": { |     "mrmime": { | ||||||
|       "version": "1.0.0", |       "version": "1.0.0", | ||||||
| @@ -24722,32 +24722,6 @@ | |||||||
|       "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", |       "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "terser": { |  | ||||||
|       "version": "5.14.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", |  | ||||||
|       "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", |  | ||||||
|       "dev": true, |  | ||||||
|       "requires": { |  | ||||||
|         "@jridgewell/source-map": "^0.3.2", |  | ||||||
|         "acorn": "^8.5.0", |  | ||||||
|         "commander": "^2.20.0", |  | ||||||
|         "source-map-support": "~0.5.20" |  | ||||||
|       }, |  | ||||||
|       "dependencies": { |  | ||||||
|         "acorn": { |  | ||||||
|           "version": "8.8.0", |  | ||||||
|           "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", |  | ||||||
|           "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", |  | ||||||
|           "dev": true |  | ||||||
|         }, |  | ||||||
|         "commander": { |  | ||||||
|           "version": "2.20.3", |  | ||||||
|           "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", |  | ||||||
|           "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", |  | ||||||
|           "dev": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "terser-webpack-plugin": { |     "terser-webpack-plugin": { | ||||||
|       "version": "5.3.0", |       "version": "5.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz", |       "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz", | ||||||
| @@ -24761,6 +24735,20 @@ | |||||||
|         "terser": "^5.7.2" |         "terser": "^5.7.2" | ||||||
|       }, |       }, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|  |         "acorn": { | ||||||
|  |           "version": "8.7.0", | ||||||
|  |           "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", | ||||||
|  |           "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", | ||||||
|  |           "dev": true, | ||||||
|  |           "optional": true, | ||||||
|  |           "peer": true | ||||||
|  |         }, | ||||||
|  |         "commander": { | ||||||
|  |           "version": "2.20.3", | ||||||
|  |           "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", | ||||||
|  |           "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", | ||||||
|  |           "dev": true | ||||||
|  |         }, | ||||||
|         "has-flag": { |         "has-flag": { | ||||||
|           "version": "4.0.0", |           "version": "4.0.0", | ||||||
|           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", |           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", | ||||||
| @@ -24803,6 +24791,25 @@ | |||||||
|           "requires": { |           "requires": { | ||||||
|             "has-flag": "^4.0.0" |             "has-flag": "^4.0.0" | ||||||
|           } |           } | ||||||
|  |         }, | ||||||
|  |         "terser": { | ||||||
|  |           "version": "5.10.0", | ||||||
|  |           "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", | ||||||
|  |           "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", | ||||||
|  |           "dev": true, | ||||||
|  |           "requires": { | ||||||
|  |             "commander": "^2.20.0", | ||||||
|  |             "source-map": "~0.7.2", | ||||||
|  |             "source-map-support": "~0.5.20" | ||||||
|  |           }, | ||||||
|  |           "dependencies": { | ||||||
|  |             "source-map": { | ||||||
|  |               "version": "0.7.3", | ||||||
|  |               "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", | ||||||
|  |               "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", | ||||||
|  |               "dev": true | ||||||
|  |             } | ||||||
|  |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "ucentral-client", |   "name": "ucentral-client", | ||||||
|   "version": "2.7.0(8)", |   "version": "2.6.29", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@coreui/coreui": "^3.4.0", |     "@coreui/coreui": "^3.4.0", | ||||||
|     "@coreui/icons": "^2.0.1", |     "@coreui/icons": "^2.0.1", | ||||||
|   | |||||||
| @@ -326,7 +326,6 @@ | |||||||
| 	"device": { | 	"device": { | ||||||
| 		"add_to_blacklist": "Gerät zur Blacklist hinzufügen", | 		"add_to_blacklist": "Gerät zur Blacklist hinzufügen", | ||||||
| 		"all_devices": "Alle Geräte", | 		"all_devices": "Alle Geräte", | ||||||
| 		"already_running_command": "Gerät führt bereits einen Befehl aus, bitte versuchen Sie es später erneut", |  | ||||||
| 		"blacklisted_on": "Datum", | 		"blacklisted_on": "Datum", | ||||||
| 		"capabilities": "Fähigkeiten", | 		"capabilities": "Fähigkeiten", | ||||||
| 		"certificate_explanation": "Zertifikate der angeschlossenen Geräte", | 		"certificate_explanation": "Zertifikate der angeschlossenen Geräte", | ||||||
| @@ -338,7 +337,6 @@ | |||||||
| 		"error_fetching_devices": "Fehler beim Abrufen von Geräten: {{error}}", | 		"error_fetching_devices": "Fehler beim Abrufen von Geräten: {{error}}", | ||||||
| 		"firmware_count_explanation": "Dies ist die Gesamtzahl der Geräte, die diesem Firmware-Server hinzugefügt wurden, einschließlich der Geräte, die derzeit nicht auf den zugehörigen Gateway-Server verweisen.", | 		"firmware_count_explanation": "Dies ist die Gesamtzahl der Geräte, die diesem Firmware-Server hinzugefügt wurden, einschließlich der Geräte, die derzeit nicht auf den zugehörigen Gateway-Server verweisen.", | ||||||
| 		"health_explanation": "Zustand der verbundenen Geräte ((Geräte = 100 % * 100 + Geräte > 90 % * 95 + Geräte > 60 % * 75 + Geräte < 60 % * 35) / Verbundene Geräte)", | 		"health_explanation": "Zustand der verbundenen Geräte ((Geräte = 100 % * 100 + Geräte > 90 % * 95 + Geräte > 60 % * 75 + Geräte < 60 % * 35) / Verbundene Geräte)", | ||||||
| 		"mac_not_found": "Seriennummer nicht gefunden, Sie werden zur Seite „Geräte“ weitergeleitet", |  | ||||||
| 		"memory_explanation": "Anzahl verbundener Geräte mit entsprechendem belegtem Speicher %", | 		"memory_explanation": "Anzahl verbundener Geräte mit entsprechendem belegtem Speicher %", | ||||||
| 		"remove_from_blacklist": "Von der schwarzen Liste entfernen", | 		"remove_from_blacklist": "Von der schwarzen Liste entfernen", | ||||||
| 		"success_added_blacklist": "Gerät erfolgreich zur Blacklist hinzugefügt!", | 		"success_added_blacklist": "Gerät erfolgreich zur Blacklist hinzugefügt!", | ||||||
|   | |||||||
| @@ -326,7 +326,6 @@ | |||||||
| 	"device": { | 	"device": { | ||||||
| 		"add_to_blacklist": "Add Device To Blacklist", | 		"add_to_blacklist": "Add Device To Blacklist", | ||||||
| 		"all_devices": "All Devices", | 		"all_devices": "All Devices", | ||||||
| 		"already_running_command": "Device is already executing a command, please try later", |  | ||||||
| 		"blacklisted_on": "Date", | 		"blacklisted_on": "Date", | ||||||
| 		"capabilities": "Capabilities", | 		"capabilities": "Capabilities", | ||||||
| 		"certificate_explanation": "Certificates of connected devices", | 		"certificate_explanation": "Certificates of connected devices", | ||||||
| @@ -338,7 +337,6 @@ | |||||||
| 		"error_fetching_devices": "Error while fetching devices: {{error}}", | 		"error_fetching_devices": "Error while fetching devices: {{error}}", | ||||||
| 		"firmware_count_explanation": "This is the total amount of devices that were added to this firmware server, including devices not currently pointing at the related gateway server.", | 		"firmware_count_explanation": "This is the total amount of devices that were added to this firmware server, including devices not currently pointing at the related gateway server.", | ||||||
| 		"health_explanation": "Health of connected devices ((Devices=100% * 100 + Devices>90% * 95 + Devices>60% * 75 + Devices<60% * 35) / ConnectedDevices)", | 		"health_explanation": "Health of connected devices ((Devices=100% * 100 + Devices>90% * 95 + Devices>60% * 75 + Devices<60% * 35) / ConnectedDevices)", | ||||||
| 		"mac_not_found": "Serial number not found, redirecting you to the Devices page", |  | ||||||
| 		"memory_explanation": "Amount of connected devices with corresponding memory used percentage", | 		"memory_explanation": "Amount of connected devices with corresponding memory used percentage", | ||||||
| 		"remove_from_blacklist": "Remove from blacklist", | 		"remove_from_blacklist": "Remove from blacklist", | ||||||
| 		"success_added_blacklist": "Device successfully added to blacklist!", | 		"success_added_blacklist": "Device successfully added to blacklist!", | ||||||
|   | |||||||
| @@ -326,7 +326,6 @@ | |||||||
| 	"device": { | 	"device": { | ||||||
| 		"add_to_blacklist": "Agregar dispositivo a la lista negra", | 		"add_to_blacklist": "Agregar dispositivo a la lista negra", | ||||||
| 		"all_devices": "Todos los dispositivos", | 		"all_devices": "Todos los dispositivos", | ||||||
| 		"already_running_command": "El dispositivo ya está ejecutando un comando, intente más tarde", |  | ||||||
| 		"blacklisted_on": "Fecha", | 		"blacklisted_on": "Fecha", | ||||||
| 		"capabilities": "capacidades", | 		"capabilities": "capacidades", | ||||||
| 		"certificate_explanation": "Certificados de dispositivos conectados", | 		"certificate_explanation": "Certificados de dispositivos conectados", | ||||||
| @@ -338,7 +337,6 @@ | |||||||
| 		"error_fetching_devices": "Error al recuperar dispositivos: {{error}}", | 		"error_fetching_devices": "Error al recuperar dispositivos: {{error}}", | ||||||
| 		"firmware_count_explanation": "Esta es la cantidad total de dispositivos que se agregaron a este servidor de firmware, incluidos los dispositivos que actualmente no apuntan al servidor de puerta de enlace relacionado.", | 		"firmware_count_explanation": "Esta es la cantidad total de dispositivos que se agregaron a este servidor de firmware, incluidos los dispositivos que actualmente no apuntan al servidor de puerta de enlace relacionado.", | ||||||
| 		"health_explanation": "Estado de los dispositivos conectados ((Dispositivos = 100% * 100 + Dispositivos> 90% * 95 + Dispositivos> 60% * 75 + Dispositivos <60% * 35) / Dispositivos conectados)", | 		"health_explanation": "Estado de los dispositivos conectados ((Dispositivos = 100% * 100 + Dispositivos> 90% * 95 + Dispositivos> 60% * 75 + Dispositivos <60% * 35) / Dispositivos conectados)", | ||||||
| 		"mac_not_found": "Número de serie no encontrado, lo redirige a la página Dispositivos", |  | ||||||
| 		"memory_explanation": "Cantidad de dispositivos conectados con la memoria correspondiente utilizada%", | 		"memory_explanation": "Cantidad de dispositivos conectados con la memoria correspondiente utilizada%", | ||||||
| 		"remove_from_blacklist": "ELIMINAR DE LA LISTA NEGRA", | 		"remove_from_blacklist": "ELIMINAR DE LA LISTA NEGRA", | ||||||
| 		"success_added_blacklist": "¡Dispositivo agregado exitosamente a la lista negra!", | 		"success_added_blacklist": "¡Dispositivo agregado exitosamente a la lista negra!", | ||||||
|   | |||||||
| @@ -326,7 +326,6 @@ | |||||||
| 	"device": { | 	"device": { | ||||||
| 		"add_to_blacklist": "Ajouter un appareil à la liste noire", | 		"add_to_blacklist": "Ajouter un appareil à la liste noire", | ||||||
| 		"all_devices": "Tous les dispositifs", | 		"all_devices": "Tous les dispositifs", | ||||||
| 		"already_running_command": "L'appareil exécute déjà une commande, veuillez réessayer plus tard", |  | ||||||
| 		"blacklisted_on": "Rendez-vous amoureux", | 		"blacklisted_on": "Rendez-vous amoureux", | ||||||
| 		"capabilities": "Capacités", | 		"capabilities": "Capacités", | ||||||
| 		"certificate_explanation": "Certificats des appareils connectés", | 		"certificate_explanation": "Certificats des appareils connectés", | ||||||
| @@ -338,7 +337,6 @@ | |||||||
| 		"error_fetching_devices": "Erreur lors de la récupération des appareils : {{error}}", | 		"error_fetching_devices": "Erreur lors de la récupération des appareils : {{error}}", | ||||||
| 		"firmware_count_explanation": "Il s'agit du nombre total d'appareils qui ont été ajoutés à ce serveur de micrologiciel, y compris les appareils qui ne pointent pas actuellement vers le serveur de passerelle associé.", | 		"firmware_count_explanation": "Il s'agit du nombre total d'appareils qui ont été ajoutés à ce serveur de micrologiciel, y compris les appareils qui ne pointent pas actuellement vers le serveur de passerelle associé.", | ||||||
| 		"health_explanation": "Santé des appareils connectés ((Appareils = 100 % * 100 + Appareils> 90 % * 95 + Appareils> 60 % * 75 + Appareils < 60 % * 35) / Appareils connectés)", | 		"health_explanation": "Santé des appareils connectés ((Appareils = 100 % * 100 + Appareils> 90 % * 95 + Appareils> 60 % * 75 + Appareils < 60 % * 35) / Appareils connectés)", | ||||||
| 		"mac_not_found": "Numéro de série introuvable, vous redirigeant vers la page Appareils", |  | ||||||
| 		"memory_explanation": "Nombre d'appareils connectés avec la mémoire correspondante utilisée %", | 		"memory_explanation": "Nombre d'appareils connectés avec la mémoire correspondante utilisée %", | ||||||
| 		"remove_from_blacklist": "Supprimer de la liste noire", | 		"remove_from_blacklist": "Supprimer de la liste noire", | ||||||
| 		"success_added_blacklist": "Appareil ajouté avec succès à la liste noire !", | 		"success_added_blacklist": "Appareil ajouté avec succès à la liste noire !", | ||||||
|   | |||||||
| @@ -326,7 +326,6 @@ | |||||||
| 	"device": { | 	"device": { | ||||||
| 		"add_to_blacklist": "Adicionar dispositivo à lista negra", | 		"add_to_blacklist": "Adicionar dispositivo à lista negra", | ||||||
| 		"all_devices": "Todos os dispositivos", | 		"all_devices": "Todos os dispositivos", | ||||||
| 		"already_running_command": "O dispositivo já está executando um comando, tente mais tarde", |  | ||||||
| 		"blacklisted_on": "Encontro", | 		"blacklisted_on": "Encontro", | ||||||
| 		"capabilities": "Recursos", | 		"capabilities": "Recursos", | ||||||
| 		"certificate_explanation": "Certificados de dispositivos conectados", | 		"certificate_explanation": "Certificados de dispositivos conectados", | ||||||
| @@ -338,7 +337,6 @@ | |||||||
| 		"error_fetching_devices": "Erro ao buscar dispositivos: {{error}}", | 		"error_fetching_devices": "Erro ao buscar dispositivos: {{error}}", | ||||||
| 		"firmware_count_explanation": "Esta é a quantidade total de dispositivos que foram adicionados a este servidor de firmware, incluindo dispositivos que não estão apontando para o servidor de gateway relacionado.", | 		"firmware_count_explanation": "Esta é a quantidade total de dispositivos que foram adicionados a este servidor de firmware, incluindo dispositivos que não estão apontando para o servidor de gateway relacionado.", | ||||||
| 		"health_explanation": "Integridade dos dispositivos conectados ((Dispositivos = 100% * 100 + Dispositivos> 90% * 95 + Dispositivos> 60% * 75 + Dispositivos <60% * 35) / Dispositivos Conectados)", | 		"health_explanation": "Integridade dos dispositivos conectados ((Dispositivos = 100% * 100 + Dispositivos> 90% * 95 + Dispositivos> 60% * 75 + Dispositivos <60% * 35) / Dispositivos Conectados)", | ||||||
| 		"mac_not_found": "Número de série não encontrado, redirecionando você para a página Dispositivos", |  | ||||||
| 		"memory_explanation": "Quantidade de dispositivos conectados com a memória correspondente usada%", | 		"memory_explanation": "Quantidade de dispositivos conectados com a memória correspondente usada%", | ||||||
| 		"remove_from_blacklist": "Remover da lista negra", | 		"remove_from_blacklist": "Remover da lista negra", | ||||||
| 		"success_added_blacklist": "Dispositivo adicionado à lista negra com sucesso!", | 		"success_added_blacklist": "Dispositivo adicionado à lista negra com sucesso!", | ||||||
|   | |||||||
| @@ -72,18 +72,7 @@ const BlinkModal = ({ show, toggleModal }) => { | |||||||
|         } |         } | ||||||
|         toggleModal(); |         toggleModal(); | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch(() => { | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |  | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |  | ||||||
|           if (split !== undefined && split.length >= 2) { |  | ||||||
|             addToast({ |  | ||||||
|               title: t('common.error'), |  | ||||||
|               body: split[1], |  | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         setResult('error'); |         setResult('error'); | ||||||
|       }) |       }) | ||||||
|       .finally(() => { |       .finally(() => { | ||||||
|   | |||||||
| @@ -205,11 +205,10 @@ const DeviceCommands = () => { | |||||||
|  |  | ||||||
|   const columns = [ |   const columns = [ | ||||||
|     { key: 'submitted', label: t('common.submitted'), filter: false, _style: { width: '20%' } }, |     { key: 'submitted', label: t('common.submitted'), filter: false, _style: { width: '20%' } }, | ||||||
|     { key: 'command', label: t('common.command'), _style: { width: '0%' } }, |     { key: 'command', label: t('common.command'), _style: { width: '15%' } }, | ||||||
|     { key: 'status', label: t('common.status'), _style: { width: '0%' } }, |  | ||||||
|     { key: 'executed', label: t('common.executed'), filter: false, _style: { width: '16%' } }, |     { key: 'executed', label: t('common.executed'), filter: false, _style: { width: '16%' } }, | ||||||
|     { key: 'completed', label: t('common.completed'), filter: false, _style: { width: '16%' } }, |     { key: 'completed', label: t('common.completed'), filter: false, _style: { width: '16%' } }, | ||||||
|     { key: 'errorCode', label: t('common.error_code'), filter: false }, |     { key: 'errorCode', label: t('common.error_code'), filter: false, _style: { width: '8%' } }, | ||||||
|     { |     { | ||||||
|       key: 'show_buttons', |       key: 'show_buttons', | ||||||
|       label: '', |       label: '', | ||||||
| @@ -318,17 +317,16 @@ const DeviceCommands = () => { | |||||||
|                     {item.completed && item.completed !== 0 ? ( |                     {item.completed && item.completed !== 0 ? ( | ||||||
|                       <FormattedDate date={item.completed} /> |                       <FormattedDate date={item.completed} /> | ||||||
|                     ) : ( |                     ) : ( | ||||||
|                       '-' |                       'Pending' | ||||||
|                     )} |                     )} | ||||||
|                   </td> |                   </td> | ||||||
|                 ), |                 ), | ||||||
|                 status: (item) => <td className="align-middle">{item.status}</td>, |  | ||||||
|                 executed: (item) => ( |                 executed: (item) => ( | ||||||
|                   <td className="align-middle"> |                   <td className="align-middle"> | ||||||
|                     {item.executed && item.executed !== 0 ? ( |                     {item.executed && item.executed !== 0 ? ( | ||||||
|                       <FormattedDate date={item.executed} /> |                       <FormattedDate date={item.executed} /> | ||||||
|                     ) : ( |                     ) : ( | ||||||
|                       '-' |                       'Pending' | ||||||
|                     )} |                     )} | ||||||
|                   </td> |                   </td> | ||||||
|                 ), |                 ), | ||||||
| @@ -337,7 +335,7 @@ const DeviceCommands = () => { | |||||||
|                     {item.submitted && item.submitted !== '' ? ( |                     {item.submitted && item.submitted !== '' ? ( | ||||||
|                       <FormattedDate date={item.submitted} /> |                       <FormattedDate date={item.submitted} /> | ||||||
|                     ) : ( |                     ) : ( | ||||||
|                       '-' |                       'Pending' | ||||||
|                     )} |                     )} | ||||||
|                   </td> |                   </td> | ||||||
|                 ), |                 ), | ||||||
|   | |||||||
| @@ -103,17 +103,12 @@ const ConfigureModal = ({ show, toggleModal }) => { | |||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch((e) => { | ||||||
|         setResponseBody('Error while submitting command!'); |         setResponseBody('Error while submitting command!'); | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |         addToast({ | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |           title: t('common.error'), | ||||||
|           if (split !== undefined && split.length >= 2) { |           body: `${t('common.general_error')}: ${e.response?.data?.ErrorDescription}`, | ||||||
|             addToast({ |           color: 'danger', | ||||||
|               title: t('common.error'), |           autohide: true, | ||||||
|               body: split[1], |         }); | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         setHadFailure(true); |         setHadFailure(true); | ||||||
|       }) |       }) | ||||||
|       .finally(() => { |       .finally(() => { | ||||||
|   | |||||||
| @@ -54,17 +54,12 @@ const DeviceActions = ({ device }) => { | |||||||
|         if (newWindow) newWindow.opener = null; |         if (newWindow) newWindow.opener = null; | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch((e) => { | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |         addToast({ | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |           title: t('common.error'), | ||||||
|           if (split !== undefined && split.length >= 2) { |           body: t('connect.error_trying_to_connect', { error: e.response?.data?.ErrorDescription }), | ||||||
|             addToast({ |           color: 'danger', | ||||||
|               title: t('common.error'), |           autohide: true, | ||||||
|               body: split[1], |         }); | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       }) |       }) | ||||||
|       .finally(() => { |       .finally(() => { | ||||||
|         setConnectLoading(false); |         setConnectLoading(false); | ||||||
| @@ -73,20 +68,18 @@ const DeviceActions = ({ device }) => { | |||||||
|  |  | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     if (upgradeStatus.result !== undefined) { |     if (upgradeStatus.result !== undefined) { | ||||||
|       if (upgradeStatus.result.success) { |       addToast({ | ||||||
|         addToast({ |         title: upgradeStatus.result.success ? t('common.success') : t('common.error'), | ||||||
|           title: upgradeStatus.result.success ? t('common.success') : t('common.error'), |         body: upgradeStatus.result.success | ||||||
|           body: upgradeStatus.result.success |           ? t('firmware.upgrade_command_submitted') | ||||||
|             ? t('firmware.upgrade_command_submitted') |           : upgradeStatus.result.error, | ||||||
|             : upgradeStatus.result.error, |         color: upgradeStatus.result.success ? 'success' : 'danger', | ||||||
|           color: upgradeStatus.result.success ? 'success' : 'danger', |         autohide: true, | ||||||
|           autohide: true, |       }); | ||||||
|         }); |  | ||||||
|         setShowUpgradeModal(false); |  | ||||||
|       } |  | ||||||
|       setUpgradeStatus({ |       setUpgradeStatus({ | ||||||
|         loading: false, |         loading: false, | ||||||
|       }); |       }); | ||||||
|  |       setShowUpgradeModal(false); | ||||||
|     } |     } | ||||||
|   }, [upgradeStatus]); |   }, [upgradeStatus]); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -111,18 +111,7 @@ const DeviceFirmwareModal = ({ | |||||||
|           }, |           }, | ||||||
|         }); |         }); | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch(() => { | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |  | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |  | ||||||
|           if (split !== undefined && split.length >= 2) { |  | ||||||
|             addToast({ |  | ||||||
|               title: t('common.error'), |  | ||||||
|               body: split[1], |  | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         setUpgradeStatus({ |         setUpgradeStatus({ | ||||||
|           loading: false, |           loading: false, | ||||||
|           result: { |           result: { | ||||||
|   | |||||||
| @@ -1,75 +0,0 @@ | |||||||
| import React, { useState } from 'react'; |  | ||||||
| import PropTypes from 'prop-types'; |  | ||||||
| import Select, { components } from 'react-select'; |  | ||||||
| import { useTranslation } from 'react-i18next'; |  | ||||||
|  |  | ||||||
| const DeviceSearchBarInput = ({ search, results, history, action, isDisabled }) => { |  | ||||||
|   const { t } = useTranslation(); |  | ||||||
|   const [selected, setSelected] = useState(''); |  | ||||||
|   const NoOptionsMessage = (props) => ( |  | ||||||
|     <components.NoOptionsMessage {...props}> |  | ||||||
|       <span>{t('common.no_devices_found')}</span> |  | ||||||
|     </components.NoOptionsMessage> |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   const onInputChange = (value) => { |  | ||||||
|     if (value === '' || value.match('^[a-fA-F0-9-*]+$')) { |  | ||||||
|       setSelected(value); |  | ||||||
|       search(value); |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <Select |  | ||||||
|       components={{ NoOptionsMessage }} |  | ||||||
|       options={results.map((serial) => ({ label: serial, value: serial }))} |  | ||||||
|       filterOption={() => true} |  | ||||||
|       inputValue={selected} |  | ||||||
|       placeholder={t('common.search')} |  | ||||||
|       isDisabled={isDisabled} |  | ||||||
|       styles={{ |  | ||||||
|         placeholder: (provided) => ({ |  | ||||||
|           ...provided, |  | ||||||
|           // disable placeholder mouse events |  | ||||||
|           pointerEvents: 'none', |  | ||||||
|           userSelect: 'none', |  | ||||||
|           MozUserSelect: 'none', |  | ||||||
|           WebkitUserSelect: 'none', |  | ||||||
|           msUserSelect: 'none', |  | ||||||
|         }), |  | ||||||
|         input: (css) => ({ |  | ||||||
|           ...css, |  | ||||||
|           /* expand the Input Component div */ |  | ||||||
|           flex: '1 1 auto', |  | ||||||
|           /* expand the Input Component child div */ |  | ||||||
|           '> div': { |  | ||||||
|             width: '100%', |  | ||||||
|           }, |  | ||||||
|           /* expand the Input Component input */ |  | ||||||
|           input: { |  | ||||||
|             width: '100% !important', |  | ||||||
|             textAlign: 'left', |  | ||||||
|           }, |  | ||||||
|         }), |  | ||||||
|       }} |  | ||||||
|       onInputChange={onInputChange} |  | ||||||
|       onChange={(property) => |  | ||||||
|         action === null ? history.push(`/devices/${property.value}`) : action(property.value) |  | ||||||
|       } |  | ||||||
|     /> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| DeviceSearchBarInput.propTypes = { |  | ||||||
|   search: PropTypes.func.isRequired, |  | ||||||
|   results: PropTypes.instanceOf(Array).isRequired, |  | ||||||
|   history: PropTypes.instanceOf(Object).isRequired, |  | ||||||
|   isDisabled: PropTypes.bool.isRequired, |  | ||||||
|   action: PropTypes.func, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| DeviceSearchBarInput.defaultProps = { |  | ||||||
|   action: null, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export default DeviceSearchBarInput; |  | ||||||
| @@ -1,11 +1,12 @@ | |||||||
| import React, { useEffect, useState } from 'react'; | import React, { useEffect, useState } from 'react'; | ||||||
| import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||||
|  | import { useTranslation } from 'react-i18next'; | ||||||
| import { useHistory } from 'react-router-dom'; | import { useHistory } from 'react-router-dom'; | ||||||
| import { useAuth } from 'ucentral-libs'; | import { useAuth, DeviceSearchBar as SearchBar } from 'ucentral-libs'; | ||||||
| import { toJson } from 'utils/helper'; | import { toJson } from 'utils/helper'; | ||||||
| import DeviceSearchBarInput from './Input'; |  | ||||||
|  |  | ||||||
| const DeviceSearchBar = ({ action }) => { | const DeviceSearchBar = ({ action }) => { | ||||||
|  |   const { t } = useTranslation(); | ||||||
|   const history = useHistory(); |   const history = useHistory(); | ||||||
|   const { currentToken, endpoints } = useAuth(); |   const { currentToken, endpoints } = useAuth(); | ||||||
|   const [socket, setSocket] = useState(null); |   const [socket, setSocket] = useState(null); | ||||||
| @@ -13,22 +14,20 @@ const DeviceSearchBar = ({ action }) => { | |||||||
|   const [waitingSearch, setWaitingSearch] = useState(''); |   const [waitingSearch, setWaitingSearch] = useState(''); | ||||||
|  |  | ||||||
|   const search = (value) => { |   const search = (value) => { | ||||||
|     if (socket) { |     if (socket.readyState === WebSocket.OPEN) { | ||||||
|       if (socket.readyState === WebSocket.OPEN) { |       if (value.length > 1 && value.match('^[a-fA-F0-9-*]+$')) { | ||||||
|         if (value.length > 1 && value.match('^[a-fA-F0-9-*]+$')) { |         setWaitingSearch(''); | ||||||
|           setWaitingSearch(''); |         socket.send( | ||||||
|           socket.send( |           JSON.stringify({ command: 'serial_number_search', serial_prefix: value.toLowerCase() }), | ||||||
|             JSON.stringify({ command: 'serial_number_search', serial_prefix: value.toLowerCase() }), |         ); | ||||||
|           ); |  | ||||||
|         } else { |  | ||||||
|           setResults([]); |  | ||||||
|         } |  | ||||||
|       } else if (socket.readyState !== WebSocket.CONNECTING && endpoints?.owgw !== undefined) { |  | ||||||
|         setWaitingSearch(value); |  | ||||||
|         setSocket(new WebSocket(`${endpoints.owgw.replace('https', 'wss')}/api/v1/ws`)); |  | ||||||
|       } else { |       } else { | ||||||
|         setWaitingSearch(value); |         setResults([]); | ||||||
|       } |       } | ||||||
|  |     } else if (socket.readyState !== WebSocket.CONNECTING) { | ||||||
|  |       setWaitingSearch(value); | ||||||
|  |       setSocket(new WebSocket(`${endpoints.owgw.replace('https', 'wss')}/api/v1/ws`)); | ||||||
|  |     } else { | ||||||
|  |       setWaitingSearch(value); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
| @@ -60,20 +59,12 @@ const DeviceSearchBar = ({ action }) => { | |||||||
|   }, [socket]); |   }, [socket]); | ||||||
|  |  | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     if (socket === null && endpoints?.owgw !== undefined) { |     if (socket === null && endpoints?.owgw) { | ||||||
|       setSocket(new WebSocket(`${endpoints.owgw.replace('https', 'wss')}/api/v1/ws`)); |       setSocket(new WebSocket(`${endpoints.owgw.replace('https', 'wss')}/api/v1/ws`)); | ||||||
|     } |     } | ||||||
|   }, []); |   }, []); | ||||||
|  |  | ||||||
|   return ( |   return <SearchBar t={t} search={search} results={results} history={history} action={action} />; | ||||||
|     <DeviceSearchBarInput |  | ||||||
|       search={search} |  | ||||||
|       results={results} |  | ||||||
|       history={history} |  | ||||||
|       action={action} |  | ||||||
|       isDisabled={endpoints.owgw === undefined} |  | ||||||
|     /> |  | ||||||
|   ); |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| DeviceSearchBar.propTypes = { | DeviceSearchBar.propTypes = { | ||||||
|   | |||||||
| @@ -34,17 +34,12 @@ const EventQueueModal = ({ show, toggle }) => { | |||||||
|         setResult(response.data); |         setResult(response.data); | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch((e) => { | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |         addToast({ | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |           title: t('common.error'), | ||||||
|           if (split !== undefined && split.length >= 2) { |           body: t('commands.unable_queue', { error: e.response?.data?.ErrorDescription }), | ||||||
|             addToast({ |           color: 'danger', | ||||||
|               title: t('common.error'), |           autohide: true, | ||||||
|               body: split[1], |         }); | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       }) |       }) | ||||||
|       .finally(() => { |       .finally(() => { | ||||||
|         setLoading(false); |         setLoading(false); | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ import React, { useState, useEffect } from 'react'; | |||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||||
| import 'react-widgets/styles.css'; | import 'react-widgets/styles.css'; | ||||||
| import { useAuth, useDevice, useToast } from 'ucentral-libs'; | import { useAuth, useDevice } from 'ucentral-libs'; | ||||||
| import axiosInstance from 'utils/axiosInstance'; | import axiosInstance from 'utils/axiosInstance'; | ||||||
| import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody'; | import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody'; | ||||||
|  |  | ||||||
| @@ -26,7 +26,6 @@ const ConfigureModal = ({ show, toggleModal }) => { | |||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const { currentToken, endpoints } = useAuth(); |   const { currentToken, endpoints } = useAuth(); | ||||||
|   const { deviceSerialNumber } = useDevice(); |   const { deviceSerialNumber } = useDevice(); | ||||||
|   const { addToast } = useToast(); |  | ||||||
|   const [hadSuccess, setHadSuccess] = useState(false); |   const [hadSuccess, setHadSuccess] = useState(false); | ||||||
|   const [hadFailure, setHadFailure] = useState(false); |   const [hadFailure, setHadFailure] = useState(false); | ||||||
|   const [doingNow, setDoingNow] = useState(false); |   const [doingNow, setDoingNow] = useState(false); | ||||||
| @@ -75,18 +74,7 @@ const ConfigureModal = ({ show, toggleModal }) => { | |||||||
|       .then(() => { |       .then(() => { | ||||||
|         setHadSuccess(true); |         setHadSuccess(true); | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch(() => { | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |  | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |  | ||||||
|           if (split !== undefined && split.length >= 2) { |  | ||||||
|             addToast({ |  | ||||||
|               title: t('common.error'), |  | ||||||
|               body: split[1], |  | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         setResponseBody(t('commands.error')); |         setResponseBody(t('commands.error')); | ||||||
|         setHadFailure(true); |         setHadFailure(true); | ||||||
|       }) |       }) | ||||||
|   | |||||||
| @@ -1,32 +0,0 @@ | |||||||
| import React from 'react'; |  | ||||||
| import PropTypes from 'prop-types'; |  | ||||||
| import { CPopover } from '@coreui/react'; |  | ||||||
| import { formatDaysAgo, prettyDate } from 'utils/helper'; |  | ||||||
|  |  | ||||||
| const FormattedDate = ({ date, size }) => { |  | ||||||
|   if (size === 'lg') { |  | ||||||
|     return ( |  | ||||||
|       <CPopover content={prettyDate(date)} advancedOptions={{ animation: false }}> |  | ||||||
|         <h2 className="d-inline-block">{date === 0 ? '-' : formatDaysAgo(date)}</h2> |  | ||||||
|       </CPopover> |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <CPopover content={prettyDate(date)} advancedOptions={{ animation: false }}> |  | ||||||
|       <span className="d-inline-block">{date === 0 ? '-' : formatDaysAgo(date)}</span> |  | ||||||
|     </CPopover> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| FormattedDate.propTypes = { |  | ||||||
|   date: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), |  | ||||||
|   size: PropTypes.string, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| FormattedDate.defaultProps = { |  | ||||||
|   date: 0, |  | ||||||
|   size: 'md', |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export default FormattedDate; |  | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| import React, { useState, useEffect, useMemo } from 'react'; | import React, { useState, useEffect } from 'react'; | ||||||
| import { CButton, CModal, CModalHeader, CModalBody, CModalTitle, CPopover } from '@coreui/react'; | import { CButton, CModal, CModalHeader, CModalBody, CModalTitle, CPopover } from '@coreui/react'; | ||||||
| import CIcon from '@coreui/icons-react'; | import CIcon from '@coreui/icons-react'; | ||||||
| import { cilX } from '@coreui/icons'; | import { cilX } from '@coreui/icons'; | ||||||
| @@ -32,17 +32,6 @@ const LatestStatisticsModal = ({ show, toggle }) => { | |||||||
|       .catch(() => {}); |       .catch(() => {}); | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   const latestStatsString = useMemo(() => { |  | ||||||
|     if (latestStats) { |  | ||||||
|       try { |  | ||||||
|         return JSON.stringify(latestStats, null, 2); |  | ||||||
|       } catch (e) { |  | ||||||
|         return ''; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return ''; |  | ||||||
|   }, [latestStats]); |  | ||||||
|  |  | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     if (show) { |     if (show) { | ||||||
|       getLatestStats(); |       getLatestStats(); | ||||||
| @@ -63,9 +52,13 @@ const LatestStatisticsModal = ({ show, toggle }) => { | |||||||
|       </CModalHeader> |       </CModalHeader> | ||||||
|       <CModalBody> |       <CModalBody> | ||||||
|         <div style={{ textAlign: 'right' }}> |         <div style={{ textAlign: 'right' }}> | ||||||
|           <CopyToClipboardButton t={t} size="lg" content={latestStatsString} /> |           <CopyToClipboardButton | ||||||
|  |             t={t} | ||||||
|  |             size="lg" | ||||||
|  |             content={JSON.stringify(latestStats ?? {}, null, 4)} | ||||||
|  |           /> | ||||||
|         </div> |         </div> | ||||||
|         <pre className="ignore">{latestStatsString}</pre> |         <pre className="ignore">{JSON.stringify(latestStats, null, 2)}</pre> | ||||||
|       </CModalBody> |       </CModalBody> | ||||||
|     </CModal> |     </CModal> | ||||||
|   ); |   ); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| import React, { useState, useEffect, useCallback } from 'react'; | import React, { useState, useEffect, useCallback } from 'react'; | ||||||
| import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||||
| import { CSpinner, CAlert } from '@coreui/react'; | import { CSpinner } from '@coreui/react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { v4 as createUuid } from 'uuid'; | import { v4 as createUuid } from 'uuid'; | ||||||
| import axiosInstance from 'utils/axiosInstance'; | import axiosInstance from 'utils/axiosInstance'; | ||||||
| @@ -23,258 +23,230 @@ const StatisticsChartList = ({ deviceSerialNumber, setOptions, section, time }) | |||||||
|     memory: [], |     memory: [], | ||||||
|     settings: {}, |     settings: {}, | ||||||
|   }); |   }); | ||||||
|   const [error, setError] = useState(false); |  | ||||||
|  |  | ||||||
|   const transformIntoDataset = (data) => { |   const transformIntoDataset = (data) => { | ||||||
|     try { |     let sortedData = data.sort((a, b) => { | ||||||
|       let sortedData = data.sort((a, b) => { |       if (a.recorded > b.recorded) return 1; | ||||||
|         if (a.recorded > b.recorded) return 1; |       if (b.recorded > a.recorded) return -1; | ||||||
|         if (b.recorded > a.recorded) return -1; |       return 0; | ||||||
|         return 0; |     }); | ||||||
|       }); |  | ||||||
|  |  | ||||||
|       const dataLength = sortedData.length; |     const dataLength = sortedData.length; | ||||||
|       if (dataLength > 1000 && dataLength < 3000) { |     if (dataLength > 1000 && dataLength < 3000) { | ||||||
|         sortedData = sortedData.filter((dat, index) => index % 4 === 0); |       sortedData = sortedData.filter((dat, index) => index % 4 === 0); | ||||||
|       } else if (dataLength >= 3000 && dataLength < 5000) { |     } else if (dataLength >= 3000 && dataLength < 5000) { | ||||||
|         sortedData = sortedData.filter((dat, index) => index % 8 === 0); |       sortedData = sortedData.filter((dat, index) => index % 8 === 0); | ||||||
|       } else if (dataLength >= 5000 && dataLength < 7000) { |     } else if (dataLength >= 5000 && dataLength < 7000) { | ||||||
|         sortedData = sortedData.filter((dat, index) => index % 12 === 0); |       sortedData = sortedData.filter((dat, index) => index % 12 === 0); | ||||||
|       } else if (dataLength > 7000) { |     } else if (dataLength > 7000) { | ||||||
|         sortedData = sortedData.filter((dat, index) => index % 20 === 0); |       sortedData = sortedData.filter((dat, index) => index % 20 === 0); | ||||||
|       } |     } | ||||||
|  |  | ||||||
|       // Looping through data to build our memory graph data |     // Looping through data to build our memory graph data | ||||||
|       const memoryUsed = [ |     const memoryUsed = [ | ||||||
|         { |       { | ||||||
|           titleName: t('statistics.memory'), |         titleName: t('statistics.memory'), | ||||||
|           name: 'Used', |         name: 'Used', | ||||||
|           backgroundColor: 'rgb(228,102,81,0.9)', |         backgroundColor: 'rgb(228,102,81,0.9)', | ||||||
|           data: [], |         data: [], | ||||||
|           fill: true, |         fill: true, | ||||||
|         }, |       }, | ||||||
|         { |       { | ||||||
|           titleName: t('statistics.memory'), |         titleName: t('statistics.memory'), | ||||||
|           name: 'Buffered', |         name: 'Buffered', | ||||||
|           backgroundColor: 'rgb(228,102,81,0.9)', |         backgroundColor: 'rgb(228,102,81,0.9)', | ||||||
|           data: [], |         data: [], | ||||||
|           fill: true, |         fill: true, | ||||||
|         }, |       }, | ||||||
|         { |       { | ||||||
|           titleName: t('statistics.memory'), |         titleName: t('statistics.memory'), | ||||||
|           name: 'Cached', |         name: 'Cached', | ||||||
|           backgroundColor: 'rgb(228,102,81,0.9)', |         backgroundColor: 'rgb(228,102,81,0.9)', | ||||||
|           data: [], |         data: [], | ||||||
|           fill: true, |         fill: true, | ||||||
|         }, |       }, | ||||||
|       ]; |     ]; | ||||||
|  |  | ||||||
|       for (const log of sortedData) { |     for (const log of sortedData) { | ||||||
|         memoryUsed[0].data.push( |       memoryUsed[0].data.push( | ||||||
|           Math.floor((log.data.unit.memory.total - log.data.unit.memory.free) / 1024 / 1024), |         Math.floor((log.data.unit.memory.total - log.data.unit.memory.free) / 1024 / 1024), | ||||||
|         ); |  | ||||||
|         memoryUsed[1].data.push(Math.floor(log.data.unit.memory.buffered / 1024 / 1024)); |  | ||||||
|         memoryUsed[2].data.push(Math.floor(log.data.unit.memory.cached / 1024 / 1024)); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       const newUsed = memoryUsed[0].data; |  | ||||||
|       if (newUsed.length > 0) newUsed.shift(); |  | ||||||
|       memoryUsed[0].data = newUsed; |  | ||||||
|       const newBuff = memoryUsed[1].data; |  | ||||||
|       if (newBuff.length > 0) newBuff.shift(); |  | ||||||
|       memoryUsed[1].data = newBuff; |  | ||||||
|       const newCached = memoryUsed[2].data; |  | ||||||
|       if (newCached.length > 0) newCached.shift(); |  | ||||||
|       memoryUsed[2].data = newCached; |  | ||||||
|  |  | ||||||
|       // This dictionary will have a key that is the interface name and a value of it's index in the final array |  | ||||||
|       const interfaceTypes = {}; |  | ||||||
|       const interfaceList = []; |  | ||||||
|       const categories = []; |  | ||||||
|       let i = 0; |  | ||||||
|       const areSameDay = datesSameDay( |  | ||||||
|         new Date(sortedData[0].recorded * 1000), |  | ||||||
|         new Date(sortedData[sortedData.length - 1].recorded * 1000), |  | ||||||
|       ); |       ); | ||||||
|  |       memoryUsed[1].data.push(Math.floor(log.data.unit.memory.buffered / 1024 / 1024)); | ||||||
|  |       memoryUsed[2].data.push(Math.floor(log.data.unit.memory.cached / 1024 / 1024)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|       // Just building the array for all the interfaces |     const newUsed = memoryUsed[0].data; | ||||||
|       for (const log of sortedData) { |     if (newUsed.length > 0) newUsed.shift(); | ||||||
|         categories.push(areSameDay ? unixToTime(log.recorded) : prettyDate(log.recorded)); |     memoryUsed[0].data = newUsed; | ||||||
|         for (const logInterface of log.data.interfaces) { |     const newBuff = memoryUsed[1].data; | ||||||
|           if (interfaceTypes[logInterface.name] === undefined) { |     if (newBuff.length > 0) newBuff.shift(); | ||||||
|             interfaceTypes[logInterface.name] = i; |     memoryUsed[1].data = newBuff; | ||||||
|             interfaceList.push([ |     const newCached = memoryUsed[2].data; | ||||||
|               { |     if (newCached.length > 0) newCached.shift(); | ||||||
|                 titleName: logInterface.name, |     memoryUsed[2].data = newCached; | ||||||
|                 name: 'Tx', |  | ||||||
|                 backgroundColor: 'rgb(228,102,81,0.9)', |     // This dictionary will have a key that is the interface name and a value of it's index in the final array | ||||||
|                 data: [], |     const interfaceTypes = {}; | ||||||
|                 fill: false, |     const interfaceList = []; | ||||||
|               }, |     const categories = []; | ||||||
|               { |     let i = 0; | ||||||
|                 titleName: logInterface.name, |     const areSameDay = datesSameDay( | ||||||
|                 name: 'Rx', |       new Date(sortedData[0].recorded * 1000), | ||||||
|                 backgroundColor: 'rgb(0,216,255,0.9)', |       new Date(sortedData[sortedData.length - 1].recorded * 1000), | ||||||
|                 data: [], |     ); | ||||||
|                 fill: false, |  | ||||||
|               }, |     // Just building the array for all the interfaces | ||||||
|             ]); |     for (const log of sortedData) { | ||||||
|             i += 1; |       categories.push(areSameDay ? unixToTime(log.recorded) : prettyDate(log.recorded)); | ||||||
|           } |       for (const logInterface of log.data.interfaces) { | ||||||
|  |         if (interfaceTypes[logInterface.name] === undefined) { | ||||||
|  |           interfaceTypes[logInterface.name] = i; | ||||||
|  |           interfaceList.push([ | ||||||
|  |             { | ||||||
|  |               titleName: logInterface.name, | ||||||
|  |               name: 'Tx', | ||||||
|  |               backgroundColor: 'rgb(228,102,81,0.9)', | ||||||
|  |               data: [], | ||||||
|  |               fill: false, | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               titleName: logInterface.name, | ||||||
|  |               name: 'Rx', | ||||||
|  |               backgroundColor: 'rgb(0,216,255,0.9)', | ||||||
|  |               data: [], | ||||||
|  |               fill: false, | ||||||
|  |             }, | ||||||
|  |           ]); | ||||||
|  |           i += 1; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|       // Looping through all the data |     // Looping through all the data | ||||||
|       const prevTxObj = {}; |     const prevTxObj = {}; | ||||||
|       const prevRxObj = {}; |     const prevRxObj = {}; | ||||||
|       for (const log of sortedData) { |     for (const log of sortedData) { | ||||||
|         // Looping through the interfaces of the log |       // Looping through the interfaces of the log | ||||||
|         const version = log.data.version ?? 0; |       const version = log.data.version ?? 0; | ||||||
|         for (const inter of log.data.interfaces) { |       for (const inter of log.data.interfaces) { | ||||||
|           if (version > 0) { |         if (version > 0) { | ||||||
|             const prevTx = prevTxObj[inter.name] !== undefined ? prevTxObj[inter.name] : 0; |           const prevTx = prevTxObj[inter.name] !== undefined ? prevTxObj[inter.name] : 0; | ||||||
|             const prevRx = prevTxObj[inter.name] !== undefined ? prevRxObj[inter.name] : 0; |           const prevRx = prevTxObj[inter.name] !== undefined ? prevRxObj[inter.name] : 0; | ||||||
|             const tx = inter.counters ? Math.floor(inter.counters.tx_bytes / 1024) : 0; |           const tx = inter.counters ? Math.floor(inter.counters.tx_bytes / 1024) : 0; | ||||||
|             const rx = inter.counters ? Math.floor(inter.counters.rx_bytes / 1024) : 0; |           const rx = inter.counters ? Math.floor(inter.counters.rx_bytes / 1024) : 0; | ||||||
|             interfaceList[interfaceTypes[inter.name]][0].data.push(Math.max(0, tx - prevTx)); |           interfaceList[interfaceTypes[inter.name]][0].data.push(Math.max(0, tx - prevTx)); | ||||||
|             interfaceList[interfaceTypes[inter.name]][1].data.push(Math.max(0, rx - prevRx)); |           interfaceList[interfaceTypes[inter.name]][1].data.push(Math.max(0, rx - prevRx)); | ||||||
|             prevTxObj[inter.name] = tx; |           prevTxObj[inter.name] = tx; | ||||||
|             prevRxObj[inter.name] = rx; |           prevRxObj[inter.name] = rx; | ||||||
|           } else { |         } else { | ||||||
|             interfaceList[interfaceTypes[inter.name]][0].data.push( |           interfaceList[interfaceTypes[inter.name]][0].data.push( | ||||||
|               inter.counters ? Math.floor(inter.counters.tx_bytes / 1024) : 0, |             inter.counters ? Math.floor(inter.counters.tx_bytes / 1024) : 0, | ||||||
|             ); |           ); | ||||||
|             interfaceList[interfaceTypes[inter.name]][1].data.push( |           interfaceList[interfaceTypes[inter.name]][1].data.push( | ||||||
|               inter.counters ? Math.floor(inter.counters.rx_bytes / 1024) : 0, |             inter.counters ? Math.floor(inter.counters.rx_bytes / 1024) : 0, | ||||||
|             ); |           ); | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|       for (let y = 0; y < interfaceList.length; y += 1) { |     for (let y = 0; y < interfaceList.length; y += 1) { | ||||||
|         for (let z = 0; z < interfaceList[y].length; z += 1) { |       for (let z = 0; z < interfaceList[y].length; z += 1) { | ||||||
|           const newArray = interfaceList[y][z].data; |         const newArray = interfaceList[y][z].data; | ||||||
|           if (newArray.length > 0) newArray.shift(); |         if (newArray.length > 0) newArray.shift(); | ||||||
|           interfaceList[y][z].data = newArray; |         interfaceList[y][z].data = newArray; | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|       const newCategories = categories; |     const newCategories = categories; | ||||||
|       if (newCategories.length > 0) newCategories.shift(); |     if (newCategories.length > 0) newCategories.shift(); | ||||||
|       const interfaceOptions = { |     const interfaceOptions = { | ||||||
|         chart: { |       chart: { | ||||||
|           id: 'chart', |         id: 'chart', | ||||||
|         }, |       }, | ||||||
|         stroke: { |       stroke: { | ||||||
|           curve: 'smooth', |         curve: 'smooth', | ||||||
|         }, |       }, | ||||||
|         xaxis: { |       xaxis: { | ||||||
|           title: { |         title: { | ||||||
|             text: 'Time', |           text: 'Time', | ||||||
|             style: { |           style: { | ||||||
|               fontSize: '15px', |             fontSize: '15px', | ||||||
|             }, |  | ||||||
|           }, |  | ||||||
|           categories: newCategories, |  | ||||||
|           tickAmount: areSameDay ? 15 : 10, |  | ||||||
|         }, |  | ||||||
|         yaxis: { |  | ||||||
|           labels: { |  | ||||||
|             minWidth: 40, |  | ||||||
|           }, |  | ||||||
|           title: { |  | ||||||
|             text: t('statistics.data'), |  | ||||||
|             style: { |  | ||||||
|               fontSize: '15px', |  | ||||||
|             }, |  | ||||||
|           }, |           }, | ||||||
|         }, |         }, | ||||||
|         legend: { |         categories: newCategories, | ||||||
|           position: 'top', |         tickAmount: areSameDay ? 15 : 10, | ||||||
|           horizontalAlign: 'right', |       }, | ||||||
|           float: true, |       yaxis: { | ||||||
|  |         labels: { | ||||||
|  |           minWidth: 40, | ||||||
|         }, |         }, | ||||||
|       }; |         title: { | ||||||
|  |           text: t('statistics.data'), | ||||||
|  |           style: { | ||||||
|  |             fontSize: '15px', | ||||||
|  |           }, | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       legend: { | ||||||
|  |         position: 'top', | ||||||
|  |         horizontalAlign: 'right', | ||||||
|  |         float: true, | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|       const memoryOptions = { |     const memoryOptions = { | ||||||
|         chart: { |       chart: { | ||||||
|           id: 'chart', |         id: 'chart', | ||||||
|         }, |       }, | ||||||
|         stroke: { |       stroke: { | ||||||
|           curve: 'smooth', |         curve: 'smooth', | ||||||
|         }, |       }, | ||||||
|         xaxis: { |       xaxis: { | ||||||
|           tickAmount: areSameDay ? 15 : 10, |         tickAmount: areSameDay ? 15 : 10, | ||||||
|           title: { |         title: { | ||||||
|             text: 'Time', |           text: 'Time', | ||||||
|             style: { |           style: { | ||||||
|               fontSize: '15px', |             fontSize: '15px', | ||||||
|             }, |  | ||||||
|           }, |  | ||||||
|           categories, |  | ||||||
|         }, |  | ||||||
|         yaxis: { |  | ||||||
|           tickAmount: 5, |  | ||||||
|           title: { |  | ||||||
|             text: t('statistics.data_mb'), |  | ||||||
|             style: { |  | ||||||
|               fontSize: '15px', |  | ||||||
|             }, |  | ||||||
|           }, |           }, | ||||||
|         }, |         }, | ||||||
|         legend: { |         categories, | ||||||
|           position: 'top', |       }, | ||||||
|           horizontalAlign: 'right', |       yaxis: { | ||||||
|           float: true, |         tickAmount: 5, | ||||||
|  |         title: { | ||||||
|  |           text: t('statistics.data_mb'), | ||||||
|  |           style: { | ||||||
|  |             fontSize: '15px', | ||||||
|  |           }, | ||||||
|         }, |         }, | ||||||
|       }; |       }, | ||||||
|  |       legend: { | ||||||
|  |         position: 'top', | ||||||
|  |         horizontalAlign: 'right', | ||||||
|  |         float: true, | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|       const newOptions = { |     const newOptions = { | ||||||
|         interfaceList, |       interfaceList, | ||||||
|         memory: [memoryUsed], |       memory: [memoryUsed], | ||||||
|         interfaceOptions, |       interfaceOptions, | ||||||
|         memoryOptions, |       memoryOptions, | ||||||
|         start: new Date(sortedData[0].recorded * 1000).toISOString(), |       start: new Date(sortedData[0].recorded * 1000).toISOString(), | ||||||
|         end: new Date(sortedData[sortedData.length - 1].recorded * 1000).toISOString(), |       end: new Date(sortedData[sortedData.length - 1].recorded * 1000).toISOString(), | ||||||
|       }; |     }; | ||||||
|  |  | ||||||
|       if (statOptions !== newOptions) { |     if (statOptions !== newOptions) { | ||||||
|         const sectionOptions = newOptions.interfaceList.map((opt) => ({ |       const sectionOptions = newOptions.interfaceList.map((opt) => ({ | ||||||
|           value: opt[0].titleName, |         value: opt[0].titleName, | ||||||
|           label: opt[0].titleName, |         label: opt[0].titleName, | ||||||
|         })); |       })); | ||||||
|         setOptions([...sectionOptions, { value: 'memory', label: t('statistics.memory') }]); |       setOptions([...sectionOptions, { value: 'memory', label: t('statistics.memory') }]); | ||||||
|         setStatOptions({ ...newOptions }); |       setStatOptions({ ...newOptions }); | ||||||
|       } |  | ||||||
|       setError(undefined); |  | ||||||
|     } catch (e) { |  | ||||||
|       if (data?.length === 0) { |  | ||||||
|         setError('nodata'); |  | ||||||
|       } else { |  | ||||||
|         setError('error'); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   const getInterface = useCallback(() => { |   const getInterface = useCallback(() => { | ||||||
|     if (error === 'error') { |  | ||||||
|       return ( |  | ||||||
|         <div style={{ textAlign: 'center' }}> |  | ||||||
|           <CAlert color="danger" style={{ width: '240px', margin: 'auto' }}> |  | ||||||
|             Error while parsing statistics |  | ||||||
|           </CAlert> |  | ||||||
|         </div> |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|     if (error === 'nodata') { |  | ||||||
|       return ( |  | ||||||
|         <div style={{ textAlign: 'center' }}> |  | ||||||
|           <CAlert color="danger" style={{ width: '340px', margin: 'auto' }}> |  | ||||||
|             No available statistics during this time period |  | ||||||
|           </CAlert> |  | ||||||
|         </div> |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|     if (statOptions.interfaceList.length === 0) return <p>N/A</p>; |     if (statOptions.interfaceList.length === 0) return <p>N/A</p>; | ||||||
|  |  | ||||||
|     const interfaceToShow = statOptions.interfaceList.find( |     const interfaceToShow = statOptions.interfaceList.find( | ||||||
| @@ -301,9 +273,8 @@ const StatisticsChartList = ({ deviceSerialNumber, setOptions, section, time }) | |||||||
|         </div> |         </div> | ||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return <p>N/A</p>; |     return <p>N/A</p>; | ||||||
|   }, [statOptions, section, error]); |   }, [statOptions, section]); | ||||||
|  |  | ||||||
|   const getStatistics = () => { |   const getStatistics = () => { | ||||||
|     setLoading(true); |     setLoading(true); | ||||||
|   | |||||||
| @@ -25,7 +25,6 @@ const NetworkDiagram = ({ show, elements, setElements }) => { | |||||||
|         onElementsRemove={onElementsRemove} |         onElementsRemove={onElementsRemove} | ||||||
|         onLoad={onLoad} |         onLoad={onLoad} | ||||||
|         snapToGrid |         snapToGrid | ||||||
|         minZoom={0.1} |  | ||||||
|         snapGrid={[20, 20]} |         snapGrid={[20, 20]} | ||||||
|       > |       > | ||||||
|         <MiniMap |         <MiniMap | ||||||
|   | |||||||
| @@ -47,7 +47,7 @@ const associationNode = (associationInfo) => ( | |||||||
|   <div> |   <div> | ||||||
|     <CRow> |     <CRow> | ||||||
|       <CCol className="text-center"> |       <CCol className="text-center"> | ||||||
|         <h6>{associationInfo.station}</h6> |         <h6>{associationInfo.bssid}</h6> | ||||||
|       </CCol> |       </CCol> | ||||||
|     </CRow> |     </CRow> | ||||||
|     <CRow> |     <CRow> | ||||||
| @@ -92,6 +92,7 @@ const NetworkDiagram = ({ show, radios, associations }) => { | |||||||
|     // Creating the association nodes and their edges |     // Creating the association nodes and their edges | ||||||
|     for (let i = 0; i < associations.length; i += 1) { |     for (let i = 0; i < associations.length; i += 1) { | ||||||
|       const assoc = associations[i]; |       const assoc = associations[i]; | ||||||
|  |  | ||||||
|       // If the radio has not been added, we create a new unknown radio based on its index |       // If the radio has not been added, we create a new unknown radio based on its index | ||||||
|       if (radiosAdded[assoc.radio.radioIndex] === undefined) { |       if (radiosAdded[assoc.radio.radioIndex] === undefined) { | ||||||
|         newElements.push({ |         newElements.push({ | ||||||
| @@ -106,7 +107,7 @@ const NetworkDiagram = ({ show, radios, associations }) => { | |||||||
|  |  | ||||||
|       // Adding the association |       // Adding the association | ||||||
|       newElements.push({ |       newElements.push({ | ||||||
|         id: `a-${assoc.station}`, |         id: `a-${assoc.bssid}`, | ||||||
|         data: { label: associationNode(assoc) }, |         data: { label: associationNode(assoc) }, | ||||||
|         position: { |         position: { | ||||||
|           x: getX(radiosAdded[assoc.radio.radioIndex]), |           x: getX(radiosAdded[assoc.radio.radioIndex]), | ||||||
| @@ -119,9 +120,9 @@ const NetworkDiagram = ({ show, radios, associations }) => { | |||||||
|  |  | ||||||
|       // Creating the edge |       // Creating the edge | ||||||
|       newElements.push({ |       newElements.push({ | ||||||
|         id: `e-${assoc.radio.radioIndex}-${assoc.station}`, |         id: `e-${assoc.radio.radioIndex}-${assoc.bssid}`, | ||||||
|         source: `r-${assoc.radio.radioIndex}`, |         source: `r-${assoc.radio.radioIndex}`, | ||||||
|         target: `a-${assoc.station}`, |         target: `a-${assoc.bssid}`, | ||||||
|         arrowHeadType: 'arrowclosed', |         arrowHeadType: 'arrowclosed', | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -89,18 +89,7 @@ const ActionModal = ({ show, toggleModal }) => { | |||||||
|         }); |         }); | ||||||
|         toggleModal(); |         toggleModal(); | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch(() => { | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |  | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |  | ||||||
|           if (split !== undefined && split.length >= 2) { |  | ||||||
|             addToast({ |  | ||||||
|               title: t('common.error'), |  | ||||||
|               body: split[1], |  | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         setResult('error'); |         setResult('error'); | ||||||
|       }) |       }) | ||||||
|       .finally(() => { |       .finally(() => { | ||||||
|   | |||||||
| @@ -105,17 +105,12 @@ const TelemetryModal = ({ show, toggle }) => { | |||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch((e) => { | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |         addToast({ | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |           title: t('common.error'), | ||||||
|           if (split !== undefined && split.length >= 2) { |           body: t('telemetry.connection_failed', { error: e.response?.data?.ErrorDescription }), | ||||||
|             addToast({ |           color: 'danger', | ||||||
|               title: t('common.error'), |           autohide: true, | ||||||
|               body: split[1], |         }); | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       }) |       }) | ||||||
|       .finally(() => setLoading(false)); |       .finally(() => setLoading(false)); | ||||||
|   }; |   }; | ||||||
|   | |||||||
| @@ -23,14 +23,13 @@ import PropTypes from 'prop-types'; | |||||||
| import 'react-widgets/styles.css'; | import 'react-widgets/styles.css'; | ||||||
| import axiosInstance from 'utils/axiosInstance'; | import axiosInstance from 'utils/axiosInstance'; | ||||||
| import eventBus from 'utils/eventBus'; | import eventBus from 'utils/eventBus'; | ||||||
| import { LoadingButton, useAuth, useDevice, useToast } from 'ucentral-libs'; | import { LoadingButton, useAuth, useDevice } from 'ucentral-libs'; | ||||||
| import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody'; | import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody'; | ||||||
| import WaitingForTraceBody from './WaitingForTraceBody'; | import WaitingForTraceBody from './WaitingForTraceBody'; | ||||||
|  |  | ||||||
| const TraceModal = ({ show, toggleModal }) => { | const TraceModal = ({ show, toggleModal }) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const { currentToken, endpoints } = useAuth(); |   const { currentToken, endpoints } = useAuth(); | ||||||
|   const { addToast } = useToast(); |  | ||||||
|   const { deviceSerialNumber, getDeviceConnection } = useDevice(); |   const { deviceSerialNumber, getDeviceConnection } = useDevice(); | ||||||
|   const [hadSuccess, setHadSuccess] = useState(false); |   const [hadSuccess, setHadSuccess] = useState(false); | ||||||
|   const [hadFailure, setHadFailure] = useState(false); |   const [hadFailure, setHadFailure] = useState(false); | ||||||
| @@ -95,18 +94,7 @@ const TraceModal = ({ show, toggleModal }) => { | |||||||
|           setWaitingForTrace(true); |           setWaitingForTrace(true); | ||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch(() => { | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |  | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |  | ||||||
|           if (split !== undefined && split.length >= 2) { |  | ||||||
|             addToast({ |  | ||||||
|               title: t('common.error'), |  | ||||||
|               body: split[1], |  | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         setResponseBody(t('commands.error')); |         setResponseBody(t('commands.error')); | ||||||
|         setHadFailure(true); |         setHadFailure(true); | ||||||
|       }) |       }) | ||||||
|   | |||||||
| @@ -20,22 +20,31 @@ import PropTypes from 'prop-types'; | |||||||
| import axiosInstance from 'utils/axiosInstance'; | import axiosInstance from 'utils/axiosInstance'; | ||||||
| import eventBus from 'utils/eventBus'; | import eventBus from 'utils/eventBus'; | ||||||
| import { prettyDateForFile } from 'utils/helper'; | import { prettyDateForFile } from 'utils/helper'; | ||||||
| import { useAuth, useDevice, useToast } from 'ucentral-libs'; | import { useAuth, useDevice } from 'ucentral-libs'; | ||||||
| import WifiChannelTable from 'components/WifiScanResultModal/WifiChannelTable'; | import WifiChannelTable from 'components/WifiScanResultModal/WifiChannelTable'; | ||||||
| import 'react-widgets/styles.css'; | import 'react-widgets/styles.css'; | ||||||
| import { CSVLink } from 'react-csv'; | import { CSVLink } from 'react-csv'; | ||||||
|  | import Select from 'react-select'; | ||||||
| import IeDisplay from 'components/WifiScanResultModal/IeDisplay'; | import IeDisplay from 'components/WifiScanResultModal/IeDisplay'; | ||||||
| import IE_OPTIONS from './IE_OPTIONS.json'; | import IE_OPTIONS from './IE_OPTIONS.json'; | ||||||
|  |  | ||||||
| const allIes = Object.entries(IE_OPTIONS).map(([, value]) => value); | const getIeOptions = () => { | ||||||
|  |   const arr = []; | ||||||
|  |   for (const [key, value] of Object.entries(IE_OPTIONS)) { | ||||||
|  |     arr.push({ | ||||||
|  |       label: `${key} (${value})`, | ||||||
|  |       value, | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   return arr; | ||||||
|  | }; | ||||||
| const WifiScanModal = ({ show, toggleModal }) => { | const WifiScanModal = ({ show, toggleModal }) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const { currentToken, endpoints } = useAuth(); |   const { currentToken, endpoints } = useAuth(); | ||||||
|   const { deviceSerialNumber } = useDevice(); |   const { deviceSerialNumber } = useDevice(); | ||||||
|   const { addToast } = useToast(); |  | ||||||
|   const [hadSuccess, setHadSuccess] = useState(false); |   const [hadSuccess, setHadSuccess] = useState(false); | ||||||
|   const [selectedIes, setSelectedIes] = useState(undefined); |   const [selectedIes, setSelectedIes] = useState(undefined); | ||||||
|  |   const [ies, setIes] = useState([]); | ||||||
|   const [hadFailure, setHadFailure] = useState(false); |   const [hadFailure, setHadFailure] = useState(false); | ||||||
|   const [errorCode, setErrorCode] = useState(0); |   const [errorCode, setErrorCode] = useState(0); | ||||||
|   const [waiting, setWaiting] = useState(false); |   const [waiting, setWaiting] = useState(false); | ||||||
| @@ -54,6 +63,14 @@ const WifiScanModal = ({ show, toggleModal }) => { | |||||||
|     setActiveScan(!activeScan); |     setActiveScan(!activeScan); | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   const onIesChange = (v) => { | ||||||
|  |     if (v.find(({ value }) => value === '*')) { | ||||||
|  |       setIes(getIeOptions()); | ||||||
|  |     } else { | ||||||
|  |       setIes(v); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     setHadSuccess(false); |     setHadSuccess(false); | ||||||
|     setHadFailure(false); |     setHadFailure(false); | ||||||
| @@ -65,7 +82,7 @@ const WifiScanModal = ({ show, toggleModal }) => { | |||||||
|     setActiveScan(false); |     setActiveScan(false); | ||||||
|     setHideOptions(false); |     setHideOptions(false); | ||||||
|     setErrorCode(0); |     setErrorCode(0); | ||||||
|     setSelectedIes(undefined); |     setIes([]); | ||||||
|   }, [show]); |   }, [show]); | ||||||
|  |  | ||||||
|   const parseThroughList = (scanList) => { |   const parseThroughList = (scanList) => { | ||||||
| @@ -147,7 +164,7 @@ const WifiScanModal = ({ show, toggleModal }) => { | |||||||
|       override_dfs: dfs, |       override_dfs: dfs, | ||||||
|       bandwidth: bandwidth !== '' ? bandwidth : undefined, |       bandwidth: bandwidth !== '' ? bandwidth : undefined, | ||||||
|       activeScan, |       activeScan, | ||||||
|       ies: allIes, |       ies: ies?.length > 0 ? ies.map(({ value }) => value) : undefined, | ||||||
|     }; |     }; | ||||||
|     const headers = { |     const headers = { | ||||||
|       Accept: 'application/json', |       Accept: 'application/json', | ||||||
| @@ -173,18 +190,7 @@ const WifiScanModal = ({ show, toggleModal }) => { | |||||||
|           setHadFailure(true); |           setHadFailure(true); | ||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch(() => { | ||||||
|         if (e.response?.data?.ErrorDescription !== undefined) { |  | ||||||
|           const split = e.response?.data?.ErrorDescription.split(':'); |  | ||||||
|           if (split !== undefined && split.length >= 2) { |  | ||||||
|             addToast({ |  | ||||||
|               title: t('common.error'), |  | ||||||
|               body: split[1], |  | ||||||
|               color: 'danger', |  | ||||||
|               autohide: true, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         setHadFailure(true); |         setHadFailure(true); | ||||||
|       }) |       }) | ||||||
|       .finally(() => { |       .finally(() => { | ||||||
| @@ -283,6 +289,23 @@ const WifiScanModal = ({ show, toggleModal }) => { | |||||||
|               </CSelect> |               </CSelect> | ||||||
|             </CCol> |             </CCol> | ||||||
|           </CRow> |           </CRow> | ||||||
|  |           <CRow className="mt-3"> | ||||||
|  |             <CCol md="3"> | ||||||
|  |               <p className="pl-2">{t('actions.request_ie')}:</p> | ||||||
|  |             </CCol> | ||||||
|  |             <CCol> | ||||||
|  |               <Select | ||||||
|  |                 isMulti | ||||||
|  |                 closeMenuOnSelect={false} | ||||||
|  |                 name="request_ie" | ||||||
|  |                 options={[{ label: 'All', value: '*' }, ...getIeOptions()]} | ||||||
|  |                 onChange={onIesChange} | ||||||
|  |                 value={ies} | ||||||
|  |                 className="basic-multi-select" | ||||||
|  |                 classNamePrefix="select" | ||||||
|  |               /> | ||||||
|  |             </CCol> | ||||||
|  |           </CRow> | ||||||
|         </div> |         </div> | ||||||
|         <div hidden={!waiting}> |         <div hidden={!waiting}> | ||||||
|           <CRow> |           <CRow> | ||||||
| @@ -309,10 +332,10 @@ const WifiScanModal = ({ show, toggleModal }) => { | |||||||
|               </CCol> |               </CCol> | ||||||
|             </CRow> |             </CRow> | ||||||
|           )} |           )} | ||||||
|  |           {selectedIes && <IeDisplay ies={selectedIes} setIes={setSelectedIes} />} | ||||||
|           {selectedIes || channelList === null ? null : ( |           {selectedIes || channelList === null ? null : ( | ||||||
|             <WifiChannelTable channels={channelList} setIes={setSelectedIes} /> |             <WifiChannelTable channels={channelList} setIes={setSelectedIes} /> | ||||||
|           )} |           )} | ||||||
|           {selectedIes && <IeDisplay ies={selectedIes} setIes={setSelectedIes} />} |  | ||||||
|         </div> |         </div> | ||||||
|       </CModalBody> |       </CModalBody> | ||||||
|     </CModal> |     </CModal> | ||||||
|   | |||||||
| @@ -1,4 +0,0 @@ | |||||||
| export const AUTH_EXPIRED_TOKEN_CODE = 9; |  | ||||||
| export const AUTH_INVALID_TOKEN_CODE = 8; |  | ||||||
|  |  | ||||||
| export const LOGOUT_ON_SEC_ERROR_CODES = [AUTH_EXPIRED_TOKEN_CODE, AUTH_INVALID_TOKEN_CODE]; |  | ||||||
| @@ -11,7 +11,7 @@ const WebSocketContext = React.createContext({ | |||||||
|   addDeviceListener: () => {}, |   addDeviceListener: () => {}, | ||||||
| }); | }); | ||||||
|  |  | ||||||
| export const WebSocketProvider = ({ children, setNewConnectionData }) => { | export const WebSocketProvider = ({ children }) => { | ||||||
|   const { currentToken, endpoints } = useAuth(); |   const { currentToken, endpoints } = useAuth(); | ||||||
|   const [isOpen, setIsOpen] = useState(false); |   const [isOpen, setIsOpen] = useState(false); | ||||||
|   const ws = useRef(undefined); |   const ws = useRef(undefined); | ||||||
| @@ -20,9 +20,6 @@ export const WebSocketProvider = ({ children, setNewConnectionData }) => { | |||||||
|  |  | ||||||
|   const onMessage = useCallback((message) => { |   const onMessage = useCallback((message) => { | ||||||
|     const result = extractWebSocketResponse(message); |     const result = extractWebSocketResponse(message); | ||||||
|     if (result?.type === 'device_connections_statistics') { |  | ||||||
|       setNewConnectionData(result.content); |  | ||||||
|     } |  | ||||||
|     if (result?.type === 'NOTIFICATION') { |     if (result?.type === 'NOTIFICATION') { | ||||||
|       dispatch({ type: 'NEW_NOTIFICATION', notification: result.notification }); |       dispatch({ type: 'NEW_NOTIFICATION', notification: result.notification }); | ||||||
|       pushNotification(result.notification); |       pushNotification(result.notification); | ||||||
| @@ -39,29 +36,23 @@ export const WebSocketProvider = ({ children, setNewConnectionData }) => { | |||||||
|     } |     } | ||||||
|   }, []); |   }, []); | ||||||
|  |  | ||||||
|   const onStartWebSocket = () => { |   // useEffect for created the WebSocket and 'storing' it in useRef | ||||||
|     ws.current = new WebSocket(`${endpoints.owgw?.replace('https', 'wss')}/api/v1/ws`); |   useEffect(() => { | ||||||
|  |     ws.current = new WebSocket(`${endpoints.owgw.replace('https', 'wss')}/api/v1/ws`); | ||||||
|     ws.current.onopen = () => { |     ws.current.onopen = () => { | ||||||
|       setIsOpen(true); |       setIsOpen(true); | ||||||
|       ws.current?.send(`token:${currentToken}`); |       ws.current?.send(`token:${currentToken}`); | ||||||
|     }; |     }; | ||||||
|     ws.current.onclose = () => { |     ws.current.onclose = () => { | ||||||
|       setIsOpen(false); |       setIsOpen(false); | ||||||
|       setTimeout(onStartWebSocket, 3000); |  | ||||||
|     }; |     }; | ||||||
|     ws.current.onerror = () => { |     ws.current.onerror = () => { | ||||||
|       setIsOpen(false); |       setIsOpen(false); | ||||||
|     }; |     }; | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   // useEffect for created the WebSocket and 'storing' it in useRef |  | ||||||
|   useEffect(() => { |  | ||||||
|     if (endpoints?.owgw !== undefined) { |  | ||||||
|       onStartWebSocket(); |  | ||||||
|     } |  | ||||||
|     const wsCurrent = ws?.current; |     const wsCurrent = ws?.current; | ||||||
|     return () => wsCurrent?.close(); |     return () => wsCurrent?.close(); | ||||||
|   }, [endpoints]); |   }, []); | ||||||
|  |  | ||||||
|   // useEffect for generating global notifications |   // useEffect for generating global notifications | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
| @@ -74,7 +65,6 @@ export const WebSocketProvider = ({ children, setNewConnectionData }) => { | |||||||
|       if (wsCurrent) wsCurrent.removeEventListener('message', onMessage); |       if (wsCurrent) wsCurrent.removeEventListener('message', onMessage); | ||||||
|     }; |     }; | ||||||
|   }, [ws?.current]); |   }, [ws?.current]); | ||||||
|  |  | ||||||
|   const values = useMemo( |   const values = useMemo( | ||||||
|     () => ({ |     () => ({ | ||||||
|       lastMessage, |       lastMessage, | ||||||
| @@ -93,7 +83,6 @@ export const WebSocketProvider = ({ children, setNewConnectionData }) => { | |||||||
|  |  | ||||||
| WebSocketProvider.propTypes = { | WebSocketProvider.propTypes = { | ||||||
|   children: PropTypes.node.isRequired, |   children: PropTypes.node.isRequired, | ||||||
|   setNewConnectionData: PropTypes.func.isRequired, |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export const useGlobalWebSocket = () => React.useContext(WebSocketContext); | export const useGlobalWebSocket = () => React.useContext(WebSocketContext); | ||||||
|   | |||||||
| @@ -26,11 +26,30 @@ export const extractWebSocketResponse = (message) => { | |||||||
|     if (data.command_response_id) { |     if (data.command_response_id) { | ||||||
|       return { data, type: 'COMMAND' }; |       return { data, type: 'COMMAND' }; | ||||||
|     } |     } | ||||||
|     if (data.notification.type === 'device_connections_statistics') { |  | ||||||
|       return { content: data.notification.content, type: 'device_connections_statistics' }; |  | ||||||
|     } |  | ||||||
|   } catch { |   } catch { | ||||||
|     return undefined; |     return undefined; | ||||||
|   } |   } | ||||||
|   return undefined; |   return undefined; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | export const getStatusFromNotification = (notification) => { | ||||||
|  |   let status = 'success'; | ||||||
|  |   if (notification.content.warning?.length > 0) status = 'warning'; | ||||||
|  |   if (notification.content.error?.length > 0) status = 'error'; | ||||||
|  |  | ||||||
|  |   return status; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const getNotificationDescription = (t, notification) => { | ||||||
|  |   if ( | ||||||
|  |     notification.content.type === 'venue_configuration_update' || | ||||||
|  |     notification.content.type === 'entity_configuration_update' | ||||||
|  |   ) { | ||||||
|  |     return t('configurations.notification_details', { | ||||||
|  |       success: notification.content.success.length, | ||||||
|  |       warning: notification.content.warning.length, | ||||||
|  |       error: notification.content.error.length, | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   return notification.content.details; | ||||||
|  | }; | ||||||
|   | |||||||
| @@ -1,17 +0,0 @@ | |||||||
| import { useState } from 'react'; |  | ||||||
|  |  | ||||||
| const useToggle = (initialState) => { |  | ||||||
|   const [value, setValue] = useState(initialState); |  | ||||||
|  |  | ||||||
|   return [ |  | ||||||
|     value, |  | ||||||
|     () => { |  | ||||||
|       setValue(!value); |  | ||||||
|     }, |  | ||||||
|     (newValue) => { |  | ||||||
|       setValue(newValue); |  | ||||||
|     }, |  | ||||||
|   ]; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export default useToggle; |  | ||||||
| @@ -1,120 +0,0 @@ | |||||||
| import React, { useState, useEffect } from 'react'; |  | ||||||
| import axiosInstance from 'utils/axiosInstance'; |  | ||||||
| import { useAuth } from 'ucentral-libs'; |  | ||||||
| import { CPopover } from '@coreui/react'; |  | ||||||
| import { extraCompactSecondsToDetailed, secondsToDetailed } from 'utils/helper'; |  | ||||||
| import { useTranslation } from 'react-i18next'; |  | ||||||
| import PropTypes from 'prop-types'; |  | ||||||
|  |  | ||||||
| const propTypes = { |  | ||||||
|   newData: PropTypes.instanceOf(Object), |  | ||||||
| }; |  | ||||||
| const defaultProps = { |  | ||||||
|   newData: undefined, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const SidebarDevices = ({ newData }) => { |  | ||||||
|   const { t } = useTranslation(); |  | ||||||
|   const { currentToken, endpoints } = useAuth(); |  | ||||||
|   const [stats, setStats] = useState(); |  | ||||||
|   const [lastUpdate, setLastUpdate] = useState(); |  | ||||||
|   const [lastTime, setLastTime] = useState(); |  | ||||||
|  |  | ||||||
|   const getInitialStats = async () => { |  | ||||||
|     const options = { |  | ||||||
|       headers: { |  | ||||||
|         Accept: 'application/json', |  | ||||||
|         Authorization: `Bearer ${currentToken}`, |  | ||||||
|       }, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     axiosInstance |  | ||||||
|       .get(`${endpoints.owgw}/api/v1/devices?connectionStatistics=true`, options) |  | ||||||
|       .then(({ data }) => { |  | ||||||
|         setStats(data); |  | ||||||
|         setLastUpdate(new Date()); |  | ||||||
|       }) |  | ||||||
|       .catch(() => {}); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   const getTime = () => { |  | ||||||
|     if (lastTime === undefined || lastUpdate === undefined) return null; |  | ||||||
|  |  | ||||||
|     const seconds = lastTime.getTime() - lastUpdate.getTime(); |  | ||||||
|  |  | ||||||
|     return Math.max(0, Math.floor(seconds / 1000)); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   useEffect(() => { |  | ||||||
|     if (newData !== undefined && Object.keys(newData).length > 0) { |  | ||||||
|       setStats({ ...newData }); |  | ||||||
|       setLastUpdate(new Date()); |  | ||||||
|     } |  | ||||||
|   }, [newData]); |  | ||||||
|  |  | ||||||
|   useEffect(() => { |  | ||||||
|     getInitialStats(); |  | ||||||
|   }, []); |  | ||||||
|  |  | ||||||
|   useEffect(() => { |  | ||||||
|     const interval = setInterval(() => { |  | ||||||
|       setLastTime(new Date()); |  | ||||||
|     }, 1000); |  | ||||||
|     return () => { |  | ||||||
|       clearInterval(interval); |  | ||||||
|     }; |  | ||||||
|   }, []); |  | ||||||
|  |  | ||||||
|   if (!stats) { |  | ||||||
|     return null; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <div |  | ||||||
|       style={{ |  | ||||||
|         position: 'absolute', |  | ||||||
|         bottom: '0px', |  | ||||||
|         width: '100%', |  | ||||||
|         background: '#2f3d54 !important', |  | ||||||
|         backgroundColor: '#2f3d54 !important', |  | ||||||
|         borderTop: '3px solid #d8dbe0', |  | ||||||
|         color: 'white', |  | ||||||
|         textAlign: 'center', |  | ||||||
|         paddingTop: '15px', |  | ||||||
|         paddingBottom: '25px', |  | ||||||
|       }} |  | ||||||
|     > |  | ||||||
|       <h3 style={{ marginBottom: '0px' }}>{stats?.connectedDevices ?? stats?.numberOfDevices}</h3> |  | ||||||
|       <h6>Connected Devices</h6> |  | ||||||
|       <CPopover |  | ||||||
|         content={secondsToDetailed( |  | ||||||
|           stats?.averageConnectionTime ?? stats?.averageConnectedTime, |  | ||||||
|           t('common.day'), |  | ||||||
|           t('common.days'), |  | ||||||
|           t('common.hour'), |  | ||||||
|           t('common.hours'), |  | ||||||
|           t('common.minute'), |  | ||||||
|           t('common.minutes'), |  | ||||||
|           t('common.second'), |  | ||||||
|           t('common.seconds'), |  | ||||||
|         )} |  | ||||||
|       > |  | ||||||
|         <h3 style={{ marginBottom: '0px' }}> |  | ||||||
|           {extraCompactSecondsToDetailed( |  | ||||||
|             stats?.averageConnectionTime ?? stats?.averageConnectedTime, |  | ||||||
|             t('common.day'), |  | ||||||
|             t('common.days'), |  | ||||||
|             t('common.seconds'), |  | ||||||
|           )} |  | ||||||
|         </h3> |  | ||||||
|       </CPopover> |  | ||||||
|       <h6>Avg. Connection Time</h6> |  | ||||||
|       <h7 style={{ color: '#ebedef', fontStyle: 'italic' }}>{getTime()} seconds ago</h7> |  | ||||||
|     </div> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| SidebarDevices.propTypes = propTypes; |  | ||||||
| SidebarDevices.defaultProps = defaultProps; |  | ||||||
|  |  | ||||||
| export default React.memo(SidebarDevices); |  | ||||||
| @@ -1,49 +0,0 @@ | |||||||
| import React from 'react'; |  | ||||||
| import { CSidebar, CSidebarBrand, CSidebarNav } from '@coreui/react'; |  | ||||||
| import PropTypes from 'prop-types'; |  | ||||||
| import styles from './index.module.scss'; |  | ||||||
|  |  | ||||||
| const Sidebar = ({ |  | ||||||
|   showSidebar, |  | ||||||
|   setShowSidebar, |  | ||||||
|   logo, |  | ||||||
|   options, |  | ||||||
|   redirectTo, |  | ||||||
|   logoHeight, |  | ||||||
|   logoWidth, |  | ||||||
| }) => ( |  | ||||||
|   <CSidebar show={showSidebar} onShowChange={(val) => setShowSidebar(val)}> |  | ||||||
|     <CSidebarBrand className="d-md-down-none" to={redirectTo}> |  | ||||||
|       <img |  | ||||||
|         className={[styles.sidebarImgFull, 'c-sidebar-brand-full'].join(' ')} |  | ||||||
|         style={{ height: logoHeight ?? undefined, width: logoWidth ?? undefined }} |  | ||||||
|         src={logo} |  | ||||||
|         alt="OpenWifi" |  | ||||||
|       /> |  | ||||||
|       <img |  | ||||||
|         className={[styles.sidebarImgMinimized, 'c-sidebar-brand-minimized'].join(' ')} |  | ||||||
|         style={{ height: logoHeight ?? undefined, width: logoWidth ?? undefined }} |  | ||||||
|         src={logo} |  | ||||||
|         alt="OpenWifi" |  | ||||||
|       /> |  | ||||||
|     </CSidebarBrand> |  | ||||||
|     <CSidebarNav>{options}</CSidebarNav> |  | ||||||
|   </CSidebar> |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| Sidebar.propTypes = { |  | ||||||
|   showSidebar: PropTypes.string.isRequired, |  | ||||||
|   setShowSidebar: PropTypes.func.isRequired, |  | ||||||
|   logo: PropTypes.string.isRequired, |  | ||||||
|   options: PropTypes.node.isRequired, |  | ||||||
|   redirectTo: PropTypes.string.isRequired, |  | ||||||
|   logoHeight: PropTypes.string, |  | ||||||
|   logoWidth: PropTypes.string, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| Sidebar.defaultProps = { |  | ||||||
|   logoHeight: null, |  | ||||||
|   logoWidth: null, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export default React.memo(Sidebar); |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| .sidebarImgFull { |  | ||||||
|   height: 75px; |  | ||||||
|   width: 175px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .sidebarImgMinimized { |  | ||||||
|   height: 75px; |  | ||||||
|   width: 75px; |  | ||||||
| } |  | ||||||
| @@ -4,20 +4,13 @@ import routes from 'routes'; | |||||||
| import { CSidebarNavItem } from '@coreui/react'; | import { CSidebarNavItem } from '@coreui/react'; | ||||||
| import { cilBarcode, cilRouter, cilSave, cilSettings, cilPeople } from '@coreui/icons'; | import { cilBarcode, cilRouter, cilSave, cilSettings, cilPeople } from '@coreui/icons'; | ||||||
| import CIcon from '@coreui/icons-react'; | import CIcon from '@coreui/icons-react'; | ||||||
| import { Header, Footer, PageContainer, ToastProvider, useAuth } from 'ucentral-libs'; | import { Header, Sidebar, Footer, PageContainer, ToastProvider, useAuth } from 'ucentral-libs'; | ||||||
| import { WebSocketProvider } from 'contexts/WebSocketProvider'; | import { WebSocketProvider } from 'contexts/WebSocketProvider'; | ||||||
| import Sidebar from './Sidebar'; |  | ||||||
| import SidebarDevices from './Devices'; |  | ||||||
|  |  | ||||||
| const TheLayout = () => { | const TheLayout = () => { | ||||||
|   const [showSidebar, setShowSidebar] = useState('responsive'); |   const [showSidebar, setShowSidebar] = useState('responsive'); | ||||||
|   const { endpoints, currentToken, user, avatar, logout } = useAuth(); |   const { endpoints, currentToken, user, avatar, logout } = useAuth(); | ||||||
|   const { t, i18n } = useTranslation(); |   const { t, i18n } = useTranslation(); | ||||||
|   const [newConnectionData, setNewConnectionData] = useState(); |  | ||||||
|  |  | ||||||
|   const onConnectionDataChange = React.useCallback((newData) => { |  | ||||||
|     setNewConnectionData({ ...newData }); |  | ||||||
|   }, []); |  | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <div className="c-app c-default-layout"> |     <div className="c-app c-default-layout"> | ||||||
| @@ -57,7 +50,6 @@ const TheLayout = () => { | |||||||
|               to="/system" |               to="/system" | ||||||
|               icon={<CIcon content={cilSettings} size="xl" className="mr-3" />} |               icon={<CIcon content={cilSettings} size="xl" className="mr-3" />} | ||||||
|             /> |             /> | ||||||
|             <SidebarDevices newData={newConnectionData} /> |  | ||||||
|           </> |           </> | ||||||
|         } |         } | ||||||
|         redirectTo="/devices" |         redirectTo="/devices" | ||||||
| @@ -79,7 +71,7 @@ const TheLayout = () => { | |||||||
|         /> |         /> | ||||||
|         <div className="c-body"> |         <div className="c-body"> | ||||||
|           <ToastProvider> |           <ToastProvider> | ||||||
|             <WebSocketProvider setNewConnectionData={onConnectionDataChange}> |             <WebSocketProvider> | ||||||
|               <PageContainer t={t} routes={routes} redirectTo="/devices" /> |               <PageContainer t={t} routes={routes} redirectTo="/devices" /> | ||||||
|             </WebSocketProvider> |             </WebSocketProvider> | ||||||
|           </ToastProvider> |           </ToastProvider> | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import React, { useEffect, useState } from 'react'; | import React, { useEffect, useState } from 'react'; | ||||||
| import { useHistory, useParams } from 'react-router-dom'; | import { useParams } from 'react-router-dom'; | ||||||
| import { CRow, CCol, CCard, CCardBody, CNav, CNavLink, CTabPane, CTabContent } from '@coreui/react'; | import { CRow, CCol, CCard, CCardBody, CNav, CNavLink, CTabPane, CTabContent } from '@coreui/react'; | ||||||
| import DeviceHealth from 'components/DeviceHealth'; | import DeviceHealth from 'components/DeviceHealth'; | ||||||
| import CommandHistory from 'components/CommandHistory'; | import CommandHistory from 'components/CommandHistory'; | ||||||
| @@ -7,7 +7,7 @@ import DeviceLogs from 'components/DeviceLogs'; | |||||||
| import DeviceStatisticsCard from 'components/InterfaceStatistics'; | import DeviceStatisticsCard from 'components/InterfaceStatistics'; | ||||||
| import DeviceActionCard from 'components/DeviceActionCard'; | import DeviceActionCard from 'components/DeviceActionCard'; | ||||||
| import axiosInstance from 'utils/axiosInstance'; | import axiosInstance from 'utils/axiosInstance'; | ||||||
| import { DeviceProvider, useAuth, useToast } from 'ucentral-libs'; | import { DeviceProvider, useAuth } from 'ucentral-libs'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import ConfigurationDisplay from 'components/ConfigurationDisplay'; | import ConfigurationDisplay from 'components/ConfigurationDisplay'; | ||||||
| import WifiAnalysis from 'components/WifiAnalysis'; | import WifiAnalysis from 'components/WifiAnalysis'; | ||||||
| @@ -23,9 +23,7 @@ const DevicePage = () => { | |||||||
|   const [index, setIndex] = useState(0); |   const [index, setIndex] = useState(0); | ||||||
|   const { currentToken, endpoints } = useAuth(); |   const { currentToken, endpoints } = useAuth(); | ||||||
|   const [lastStats, setLastStats] = useState(null); |   const [lastStats, setLastStats] = useState(null); | ||||||
|   const { addToast } = useToast(); |  | ||||||
|   const [status, setStatus] = useState(null); |   const [status, setStatus] = useState(null); | ||||||
|   const history = useHistory(); |  | ||||||
|   const [deviceConfig, setDeviceConfig] = useState(null); |   const [deviceConfig, setDeviceConfig] = useState(null); | ||||||
|   const [error, setError] = useState(false); |   const [error, setError] = useState(false); | ||||||
|   const [loading, setLoading] = useState(false); |   const [loading, setLoading] = useState(false); | ||||||
| @@ -66,16 +64,7 @@ const DevicePage = () => { | |||||||
|       .then((response) => { |       .then((response) => { | ||||||
|         if (response) setDeviceConfig({ ...deviceInfo, extendedInfo: response.data.extendedInfo }); |         if (response) setDeviceConfig({ ...deviceInfo, extendedInfo: response.data.extendedInfo }); | ||||||
|       }) |       }) | ||||||
|       .catch((e) => { |       .catch(() => { | ||||||
|         if (e.response?.status === 404 || e.response?.status === 400) { |  | ||||||
|           addToast({ |  | ||||||
|             title: t('common.error'), |  | ||||||
|             body: t('device.mac_not_found'), |  | ||||||
|             color: 'danger', |  | ||||||
|             autohide: true, |  | ||||||
|           }); |  | ||||||
|           history.push('/devices'); |  | ||||||
|         } |  | ||||||
|         setDeviceConfig(deviceInfo); |         setDeviceConfig(deviceInfo); | ||||||
|       }); |       }); | ||||||
|   }; |   }; | ||||||
|   | |||||||
| @@ -1,189 +0,0 @@ | |||||||
| import React, { useState } from 'react'; |  | ||||||
| import PropTypes from 'prop-types'; |  | ||||||
| import { |  | ||||||
|   CCard, |  | ||||||
|   CCardBody, |  | ||||||
|   CCardHeader, |  | ||||||
|   CRow, |  | ||||||
|   CCol, |  | ||||||
|   CButton, |  | ||||||
|   CPopover, |  | ||||||
|   CModal, |  | ||||||
|   CModalBody, |  | ||||||
|   CModalHeader, |  | ||||||
|   CModalTitle, |  | ||||||
|   CDataTable, |  | ||||||
| } from '@coreui/react'; |  | ||||||
| import Select from 'react-select'; |  | ||||||
| import CIcon from '@coreui/icons-react'; |  | ||||||
| import { cilSync, cilX } from '@coreui/icons'; |  | ||||||
| import { prettyDate } from 'utils/helper'; |  | ||||||
| import useToggle from 'hooks/useToggle'; |  | ||||||
| import FormattedDate from 'components/FormattedDate'; |  | ||||||
|  |  | ||||||
| const ApiStatusCard = ({ t, info, reload }) => { |  | ||||||
|   const [types, setTypes] = useState([]); |  | ||||||
|   const [showCerts, toggleCerts] = useToggle(); |  | ||||||
|  |  | ||||||
|   const submit = () => { |  | ||||||
|     reload( |  | ||||||
|       types.map((v) => v.value), |  | ||||||
|       info.endpoint, |  | ||||||
|     ); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <CCard> |  | ||||||
|       <CCardHeader className="dark-header"> |  | ||||||
|         <div style={{ fontWeight: '600' }} className=" text-value-lg float-left"> |  | ||||||
|           {info.title} |  | ||||||
|         </div> |  | ||||||
|       </CCardHeader> |  | ||||||
|       <CCardBody> |  | ||||||
|         <CRow> |  | ||||||
|           <CCol sm="4"> |  | ||||||
|             <div block="true">{t('common.endpoint')}:</div> |  | ||||||
|           </CCol> |  | ||||||
|           <CCol> |  | ||||||
|             <div block="true">{info.endpoint}</div> |  | ||||||
|           </CCol> |  | ||||||
|         </CRow> |  | ||||||
|         <CRow> |  | ||||||
|           <CCol sm="4"> |  | ||||||
|             <div block="true">{t('system.hostname')}:</div> |  | ||||||
|           </CCol> |  | ||||||
|           <CCol> |  | ||||||
|             <div block="true">{info.hostname}</div> |  | ||||||
|           </CCol> |  | ||||||
|         </CRow> |  | ||||||
|         <CRow> |  | ||||||
|           <CCol sm="4"> |  | ||||||
|             <div block="true">{t('system.os')}:</div> |  | ||||||
|           </CCol> |  | ||||||
|           <CCol> |  | ||||||
|             <div block="true">{info.os}</div> |  | ||||||
|           </CCol> |  | ||||||
|         </CRow> |  | ||||||
|         <CRow> |  | ||||||
|           <CCol sm="4"> |  | ||||||
|             <div block="true">{t('system.processors')}:</div> |  | ||||||
|           </CCol> |  | ||||||
|           <CCol> |  | ||||||
|             <div block="true">{info.processors}</div> |  | ||||||
|           </CCol> |  | ||||||
|         </CRow> |  | ||||||
|         <CRow> |  | ||||||
|           <CCol sm="4"> |  | ||||||
|             <div block="true">{t('common.start')}:</div> |  | ||||||
|           </CCol> |  | ||||||
|           <CCol> |  | ||||||
|             <div block="true"> |  | ||||||
|               {info.start ? <FormattedDate date={info.start} /> : t('common.unknown')} |  | ||||||
|             </div> |  | ||||||
|           </CCol> |  | ||||||
|         </CRow> |  | ||||||
|         <CRow> |  | ||||||
|           <CCol sm="4"> |  | ||||||
|             <div block="true">{t('status.uptime')}:</div> |  | ||||||
|           </CCol> |  | ||||||
|           <CCol> |  | ||||||
|             <div block="true">{info.uptime}</div> |  | ||||||
|           </CCol> |  | ||||||
|         </CRow> |  | ||||||
|         <CRow> |  | ||||||
|           <CCol sm="4"> |  | ||||||
|             <div block="true">{t('footer.version')}:</div> |  | ||||||
|           </CCol> |  | ||||||
|           <CCol> |  | ||||||
|             <div block="true">{info.version}</div> |  | ||||||
|           </CCol> |  | ||||||
|         </CRow> |  | ||||||
|         <CRow> |  | ||||||
|           <CCol sm="4"> |  | ||||||
|             <div block="true">{t('common.certificates')}:</div> |  | ||||||
|           </CCol> |  | ||||||
|           <CCol> |  | ||||||
|             <div block="true"> |  | ||||||
|               {info.certificates?.length > 0 ? ( |  | ||||||
|                 <CButton className="ml-0 pl-0 py-0" color="link" onClick={toggleCerts}> |  | ||||||
|                   {t('common.details')} ({info.certificates.length}) |  | ||||||
|                 </CButton> |  | ||||||
|               ) : ( |  | ||||||
|                 <div>{t('common.unknown')}</div> |  | ||||||
|               )} |  | ||||||
|             </div> |  | ||||||
|           </CCol> |  | ||||||
|         </CRow> |  | ||||||
|         <CRow> |  | ||||||
|           <CCol sm="4" className="pt-1"> |  | ||||||
|             <div block="true">{t('system.reload_subsystems')}:</div> |  | ||||||
|           </CCol> |  | ||||||
|           <CCol> |  | ||||||
|             <div block="true"> |  | ||||||
|               {info.subsystems.length === 0 ? ( |  | ||||||
|                 t('common.unknown') |  | ||||||
|               ) : ( |  | ||||||
|                 <div> |  | ||||||
|                   <div className="float-left" style={{ width: '85%' }}> |  | ||||||
|                     <Select |  | ||||||
|                       isMulti |  | ||||||
|                       closeMenuOnSelect={false} |  | ||||||
|                       name="Subsystems" |  | ||||||
|                       options={info.subsystems.map((sys) => ({ value: sys, label: sys }))} |  | ||||||
|                       onChange={setTypes} |  | ||||||
|                       value={types} |  | ||||||
|                       className="basic-multi-select" |  | ||||||
|                       classNamePrefix="select" |  | ||||||
|                     /> |  | ||||||
|                   </div> |  | ||||||
|                   <div className="float-left text-right" style={{ width: '15%' }}> |  | ||||||
|                     <CPopover content={t('system.reload')}> |  | ||||||
|                       <CButton |  | ||||||
|                         color="primary" |  | ||||||
|                         variant="outline" |  | ||||||
|                         onClick={submit} |  | ||||||
|                         disabled={types.length === 0} |  | ||||||
|                       > |  | ||||||
|                         <CIcon content={cilSync} /> |  | ||||||
|                       </CButton> |  | ||||||
|                     </CPopover> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|               )} |  | ||||||
|             </div> |  | ||||||
|           </CCol> |  | ||||||
|         </CRow> |  | ||||||
|       </CCardBody> |  | ||||||
|       <CModal size="lg" show={showCerts} onClose={toggleCerts}> |  | ||||||
|         <CModalHeader className="p-1"> |  | ||||||
|           <CModalTitle className="pl-1 pt-1">{t('common.certificates')}</CModalTitle> |  | ||||||
|           <div className="text-right"> |  | ||||||
|             <CPopover content={t('common.close')}> |  | ||||||
|               <CButton color="primary" variant="outline" className="ml-2" onClick={toggleCerts}> |  | ||||||
|                 <CIcon content={cilX} /> |  | ||||||
|               </CButton> |  | ||||||
|             </CPopover> |  | ||||||
|           </div> |  | ||||||
|         </CModalHeader> |  | ||||||
|         <CModalBody> |  | ||||||
|           <CDataTable |  | ||||||
|             addTableClasses="table-sm" |  | ||||||
|             border |  | ||||||
|             items={info?.certificates.map((cert) => ({ |  | ||||||
|               ...cert, |  | ||||||
|               expiresOn: prettyDate(cert.expiresOn), |  | ||||||
|             }))} |  | ||||||
|           /> |  | ||||||
|         </CModalBody> |  | ||||||
|       </CModal> |  | ||||||
|     </CCard> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| ApiStatusCard.propTypes = { |  | ||||||
|   t: PropTypes.func.isRequired, |  | ||||||
|   info: PropTypes.instanceOf(Object).isRequired, |  | ||||||
|   reload: PropTypes.func.isRequired, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export default React.memo(ApiStatusCard); |  | ||||||
| @@ -1,135 +1,22 @@ | |||||||
| import React, { useState, useEffect } from 'react'; | import React from 'react'; | ||||||
| import { v4 as createUuid } from 'uuid'; |  | ||||||
| import { CRow, CCol } from '@coreui/react'; |  | ||||||
| import { useAuth, useToast } from 'ucentral-libs'; |  | ||||||
| import { secondsToDetailed } from 'utils/helper'; |  | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
|  | import { SystemPage as Page, useToast, useAuth } from 'ucentral-libs'; | ||||||
| import axiosInstance from 'utils/axiosInstance'; | import axiosInstance from 'utils/axiosInstance'; | ||||||
| import ApiStatusCard from './ApiStatusCard'; |  | ||||||
|  |  | ||||||
| const SystemPage = () => { | const SystemPage = () => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const { currentToken, endpoints } = useAuth(); |   const { currentToken, endpoints } = useAuth(); | ||||||
|   const { addToast } = useToast(); |   const { addToast } = useToast(); | ||||||
|   const [endpointsInfo, setEndpointsInfo] = useState([]); |  | ||||||
|  |  | ||||||
|   const getSystemInfo = async (key, endpoint) => { |  | ||||||
|     let systemInfo = { |  | ||||||
|       title: key, |  | ||||||
|       endpoint, |  | ||||||
|       hostname: t('common.unknown'), |  | ||||||
|       os: t('common.unknown'), |  | ||||||
|       processors: t('common.unknown'), |  | ||||||
|       uptime: t('common.unknown'), |  | ||||||
|       version: t('common.unknown'), |  | ||||||
|       certificates: [], |  | ||||||
|       subsystems: [], |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     const options = { |  | ||||||
|       headers: { |  | ||||||
|         Accept: 'application/json', |  | ||||||
|         Authorization: `Bearer ${currentToken}`, |  | ||||||
|       }, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     await axiosInstance |  | ||||||
|       .get(`${endpoint}/api/v1/system?command=info`, options) |  | ||||||
|       .then((newInfo) => { |  | ||||||
|         systemInfo = { ...systemInfo, ...newInfo.data }; |  | ||||||
|         systemInfo.uptime = secondsToDetailed( |  | ||||||
|           newInfo.data.uptime, |  | ||||||
|           t('common.day'), |  | ||||||
|           t('common.days'), |  | ||||||
|           t('common.hour'), |  | ||||||
|           t('common.hours'), |  | ||||||
|           t('common.minute'), |  | ||||||
|           t('common.minutes'), |  | ||||||
|           t('common.second'), |  | ||||||
|           t('common.seconds'), |  | ||||||
|         ); |  | ||||||
|         systemInfo.start = newInfo.data.start; |  | ||||||
|       }) |  | ||||||
|       .catch(() => {}); |  | ||||||
|     await axiosInstance |  | ||||||
|       .post(`${endpoint}/api/v1/system`, { command: 'getsubsystemnames' }, options) |  | ||||||
|       .then((newSubs) => { |  | ||||||
|         systemInfo.subsystems = newSubs.data.list.sort((a, b) => { |  | ||||||
|           if (a < b) return -1; |  | ||||||
|           if (a > b) return 1; |  | ||||||
|           return 0; |  | ||||||
|         }); |  | ||||||
|       }) |  | ||||||
|       .catch(() => {}); |  | ||||||
|  |  | ||||||
|     return systemInfo; |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   const reload = (subsystems, endpoint) => { |  | ||||||
|     const options = { |  | ||||||
|       headers: { |  | ||||||
|         Accept: 'application/json', |  | ||||||
|         Authorization: `Bearer ${currentToken}`, |  | ||||||
|       }, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     const parameters = { |  | ||||||
|       command: 'reload', |  | ||||||
|       subsystems, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     axiosInstance |  | ||||||
|       .post(`${endpoint}/api/v1/system?command=info`, parameters, options) |  | ||||||
|       .then(() => { |  | ||||||
|         addToast({ |  | ||||||
|           title: t('common.success'), |  | ||||||
|           body: t('system.success_reload'), |  | ||||||
|           color: 'success', |  | ||||||
|           autohide: true, |  | ||||||
|         }); |  | ||||||
|       }) |  | ||||||
|       .catch((e) => { |  | ||||||
|         addToast({ |  | ||||||
|           title: t('common.error'), |  | ||||||
|           body: t('system.error_reloading', { error: e.response?.data?.ErrorDescription }), |  | ||||||
|           color: 'danger', |  | ||||||
|           autohide: true, |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   const getAllInfo = async () => { |  | ||||||
|     const promises = []; |  | ||||||
|  |  | ||||||
|     for (const [key, value] of Object.entries(endpoints)) { |  | ||||||
|       promises.push(getSystemInfo(key, value)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     try { |  | ||||||
|       const results = await Promise.all(promises); |  | ||||||
|       setEndpointsInfo(results); |  | ||||||
|     } catch (e) { |  | ||||||
|       addToast({ |  | ||||||
|         title: t('common.error'), |  | ||||||
|         body: t('system.error_fetching'), |  | ||||||
|         color: 'danger', |  | ||||||
|         autohide: true, |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   useEffect(() => { |  | ||||||
|     getAllInfo(); |  | ||||||
|   }, []); |  | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <CRow> |     <Page | ||||||
|       {endpointsInfo.map((info) => ( |       t={t} | ||||||
|         <CCol sm="12" lg="6" xxl="4" key={createUuid()}> |       currentToken={currentToken} | ||||||
|           <ApiStatusCard t={t} info={info} reload={reload} /> |       endpoints={endpoints} | ||||||
|         </CCol> |       addToast={addToast} | ||||||
|       ))} |       axiosInstance={axiosInstance} | ||||||
|     </CRow> |     /> | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export default SystemPage; | export default SystemPage; | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ const Routes = () => { | |||||||
|       path="/" |       path="/" | ||||||
|       name="Devices" |       name="Devices" | ||||||
|       render={(props) => |       render={(props) => | ||||||
|         currentToken !== '' && endpoints && Object.keys(endpoints).length !== 0 ? ( |         currentToken !== '' && Object.keys(endpoints).length !== 0 ? ( | ||||||
|           <TheLayout {...props} /> |           <TheLayout {...props} /> | ||||||
|         ) : ( |         ) : ( | ||||||
|           <ToastProvider> |           <ToastProvider> | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| import * as axios from 'axios'; | import * as axios from 'axios'; | ||||||
| import axiosRetry from 'axios-retry'; | import axiosRetry from 'axios-retry'; | ||||||
| import { LOGOUT_ON_SEC_ERROR_CODES } from 'constants'; |  | ||||||
|  |  | ||||||
| const axiosInstance = axios.create(); | const axiosInstance = axios.create(); | ||||||
|  |  | ||||||
| @@ -28,7 +27,7 @@ axiosInstance.interceptors.response.use( | |||||||
|           retries += 1; |           retries += 1; | ||||||
|           localStorage.setItem('sec_retries', retries); |           localStorage.setItem('sec_retries', retries); | ||||||
|         } |         } | ||||||
|         if (LOGOUT_ON_SEC_ERROR_CODES.includes(error.response.data?.ErrorCode)) { |         if (error.response.data?.ErrorCode === 9) { | ||||||
|           localStorage.removeItem('access_token'); |           localStorage.removeItem('access_token'); | ||||||
|           localStorage.removeItem('gateway_endpoints'); |           localStorage.removeItem('gateway_endpoints'); | ||||||
|           sessionStorage.clear(); |           sessionStorage.clear(); | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | export const cleanTimestamp = (timestamp) => timestamp.replace('T', ' ').replace('Z', ' '); | ||||||
|  |  | ||||||
| export const cleanBytesString = (bytes, decimals = 2) => { | export const cleanBytesString = (bytes, decimals = 2) => { | ||||||
|   const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; |   const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; | ||||||
|   if (!bytes || bytes === 0) { |   if (!bytes || bytes === 0) { | ||||||
| @@ -130,25 +132,6 @@ export const compactSecondsToDetailed = (seconds, dayLabel, daysLabel, secondsLa | |||||||
|   return finalString; |   return finalString; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export const extraCompactSecondsToDetailed = (seconds) => { |  | ||||||
|   let secondsLeft = seconds; |  | ||||||
|   const days = Math.floor(secondsLeft / (3600 * 24)); |  | ||||||
|   secondsLeft -= days * (3600 * 24); |  | ||||||
|   const hours = Math.floor(secondsLeft / 3600); |  | ||||||
|   secondsLeft -= hours * 3600; |  | ||||||
|   const minutes = Math.floor(secondsLeft / 60); |  | ||||||
|   secondsLeft -= minutes * 60; |  | ||||||
|  |  | ||||||
|   let finalString = ''; |  | ||||||
|  |  | ||||||
|   finalString = `${finalString}${prettyNumber(days)}:`; |  | ||||||
|   finalString = `${finalString}${prettyNumber(hours)}:`; |  | ||||||
|   finalString = `${finalString}${prettyNumber(minutes)}:`; |  | ||||||
|   finalString = `${finalString}${prettyNumber(secondsLeft)}`; |  | ||||||
|  |  | ||||||
|   return finalString; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const validateEmail = (email) => { | export const validateEmail = (email) => { | ||||||
|   const regex = /\S+@\S+\.\S+/; |   const regex = /\S+@\S+\.\S+/; | ||||||
|   return regex.test(email); |   return regex.test(email); | ||||||
| @@ -160,25 +143,3 @@ export const testRegex = (value, regexString) => { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| export const datesSameDay = (first, second) => first.getDate() === second.getDate(); | export const datesSameDay = (first, second) => first.getDate() === second.getDate(); | ||||||
|  |  | ||||||
| const units = { |  | ||||||
|   year: 24 * 60 * 60 * 1000 * 365, |  | ||||||
|   month: (24 * 60 * 60 * 1000 * 365) / 12, |  | ||||||
|   day: 24 * 60 * 60 * 1000, |  | ||||||
|   hour: 60 * 60 * 1000, |  | ||||||
|   minute: 60 * 1000, |  | ||||||
|   second: 1000, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const rtf = new Intl.RelativeTimeFormat('en', { localeMatcher: 'best fit', style: 'long' }); |  | ||||||
| export const formatDaysAgo = (d1, d2 = new Date()) => { |  | ||||||
|   const convertedTimestamp = unixToDateString(d1); |  | ||||||
|   const date = new Date(convertedTimestamp); |  | ||||||
|   const elapsed = date - d2; |  | ||||||
|  |  | ||||||
|   for (const [key] of Object.entries(units)) |  | ||||||
|     if (Math.abs(elapsed) > units[key] || key === 'second') |  | ||||||
|       return rtf.format(Math.round(elapsed / units[key]), key); |  | ||||||
|  |  | ||||||
|   return prettyDate(date); |  | ||||||
| }; |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user