mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui.git
				synced 2025-10-31 18:57:46 +00:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 8d8b1e3945 | ||
|   | c869b5c077 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -18,4 +18,3 @@ | |||||||
| .env.production.local | .env.production.local | ||||||
|  |  | ||||||
| npm-debug.log* | npm-debug.log* | ||||||
| .vscode/settings.json |  | ||||||
|   | |||||||
| @@ -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: v3.0.0 |     tag: v2.11.0 | ||||||
|     pullPolicy: Always |     pullPolicy: Always | ||||||
|  |  | ||||||
| services: | services: | ||||||
|   | |||||||
							
								
								
									
										154
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										154
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,12 +1,12 @@ | |||||||
| { | { | ||||||
|   "name": "ucentral-client", |   "name": "ucentral-client", | ||||||
|   "version": "3.0.0(1)", |   "version": "2.11.0(7)", | ||||||
|   "lockfileVersion": 3, |   "lockfileVersion": 3, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "packages": { |   "packages": { | ||||||
|     "": { |     "": { | ||||||
|       "name": "ucentral-client", |       "name": "ucentral-client", | ||||||
|       "version": "3.0.0(1)", |       "version": "2.11.0(7)", | ||||||
|       "license": "ISC", |       "license": "ISC", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@chakra-ui/anatomy": "^2.1.1", |         "@chakra-ui/anatomy": "^2.1.1", | ||||||
| @@ -104,12 +104,11 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/code-frame": { |     "node_modules/@babel/code-frame": { | ||||||
|       "version": "7.22.13", |       "version": "7.21.4", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", |       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", | ||||||
|       "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", |       "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/highlight": "^7.22.13", |         "@babel/highlight": "^7.18.6" | ||||||
|         "chalk": "^2.4.2" |  | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
| @@ -155,12 +154,12 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/generator": { |     "node_modules/@babel/generator": { | ||||||
|       "version": "7.23.0", |       "version": "7.21.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", |       "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.5.tgz", | ||||||
|       "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", |       "integrity": "sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/types": "^7.23.0", |         "@babel/types": "^7.21.5", | ||||||
|         "@jridgewell/gen-mapping": "^0.3.2", |         "@jridgewell/gen-mapping": "^0.3.2", | ||||||
|         "@jridgewell/trace-mapping": "^0.3.17", |         "@jridgewell/trace-mapping": "^0.3.17", | ||||||
|         "jsesc": "^2.5.1" |         "jsesc": "^2.5.1" | ||||||
| @@ -298,34 +297,33 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/helper-environment-visitor": { |     "node_modules/@babel/helper-environment-visitor": { | ||||||
|       "version": "7.22.20", |       "version": "7.21.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz", | ||||||
|       "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", |       "integrity": "sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/helper-function-name": { |     "node_modules/@babel/helper-function-name": { | ||||||
|       "version": "7.23.0", |       "version": "7.21.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", | ||||||
|       "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", |       "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/template": "^7.22.15", |         "@babel/template": "^7.20.7", | ||||||
|         "@babel/types": "^7.23.0" |         "@babel/types": "^7.21.0" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/helper-hoist-variables": { |     "node_modules/@babel/helper-hoist-variables": { | ||||||
|       "version": "7.22.5", |       "version": "7.18.6", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", |  | ||||||
|       "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", |  | ||||||
|       "dev": true, |       "dev": true, | ||||||
|  |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/types": "^7.22.5" |         "@babel/types": "^7.18.6" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
| @@ -454,29 +452,27 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/helper-split-export-declaration": { |     "node_modules/@babel/helper-split-export-declaration": { | ||||||
|       "version": "7.22.6", |       "version": "7.18.6", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", |  | ||||||
|       "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", |  | ||||||
|       "dev": true, |       "dev": true, | ||||||
|  |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/types": "^7.22.5" |         "@babel/types": "^7.18.6" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/helper-string-parser": { |     "node_modules/@babel/helper-string-parser": { | ||||||
|       "version": "7.22.5", |       "version": "7.21.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", | ||||||
|       "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", |       "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/helper-validator-identifier": { |     "node_modules/@babel/helper-validator-identifier": { | ||||||
|       "version": "7.22.20", |       "version": "7.19.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", |       "license": "MIT", | ||||||
|       "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", |  | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
|       } |       } | ||||||
| @@ -520,12 +516,11 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/highlight": { |     "node_modules/@babel/highlight": { | ||||||
|       "version": "7.22.20", |       "version": "7.18.6", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", |       "license": "MIT", | ||||||
|       "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", |  | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/helper-validator-identifier": "^7.22.20", |         "@babel/helper-validator-identifier": "^7.18.6", | ||||||
|         "chalk": "^2.4.2", |         "chalk": "^2.0.0", | ||||||
|         "js-tokens": "^4.0.0" |         "js-tokens": "^4.0.0" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
| @@ -533,9 +528,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/parser": { |     "node_modules/@babel/parser": { | ||||||
|       "version": "7.23.0", |       "version": "7.21.8", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", |       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.8.tgz", | ||||||
|       "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", |       "integrity": "sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "parser": "bin/babel-parser.js" |         "parser": "bin/babel-parser.js" | ||||||
| @@ -1689,33 +1684,33 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/template": { |     "node_modules/@babel/template": { | ||||||
|       "version": "7.22.15", |       "version": "7.20.7", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", |       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", | ||||||
|       "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", |       "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/code-frame": "^7.22.13", |         "@babel/code-frame": "^7.18.6", | ||||||
|         "@babel/parser": "^7.22.15", |         "@babel/parser": "^7.20.7", | ||||||
|         "@babel/types": "^7.22.15" |         "@babel/types": "^7.20.7" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/traverse": { |     "node_modules/@babel/traverse": { | ||||||
|       "version": "7.23.2", |       "version": "7.21.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", |       "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.5.tgz", | ||||||
|       "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", |       "integrity": "sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/code-frame": "^7.22.13", |         "@babel/code-frame": "^7.21.4", | ||||||
|         "@babel/generator": "^7.23.0", |         "@babel/generator": "^7.21.5", | ||||||
|         "@babel/helper-environment-visitor": "^7.22.20", |         "@babel/helper-environment-visitor": "^7.21.5", | ||||||
|         "@babel/helper-function-name": "^7.23.0", |         "@babel/helper-function-name": "^7.21.0", | ||||||
|         "@babel/helper-hoist-variables": "^7.22.5", |         "@babel/helper-hoist-variables": "^7.18.6", | ||||||
|         "@babel/helper-split-export-declaration": "^7.22.6", |         "@babel/helper-split-export-declaration": "^7.18.6", | ||||||
|         "@babel/parser": "^7.23.0", |         "@babel/parser": "^7.21.5", | ||||||
|         "@babel/types": "^7.23.0", |         "@babel/types": "^7.21.5", | ||||||
|         "debug": "^4.1.0", |         "debug": "^4.1.0", | ||||||
|         "globals": "^11.1.0" |         "globals": "^11.1.0" | ||||||
|       }, |       }, | ||||||
| @@ -1724,12 +1719,12 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@babel/types": { |     "node_modules/@babel/types": { | ||||||
|       "version": "7.23.0", |       "version": "7.21.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", |       "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.5.tgz", | ||||||
|       "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", |       "integrity": "sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/helper-string-parser": "^7.22.5", |         "@babel/helper-string-parser": "^7.21.5", | ||||||
|         "@babel/helper-validator-identifier": "^7.22.20", |         "@babel/helper-validator-identifier": "^7.19.1", | ||||||
|         "to-fast-properties": "^2.0.0" |         "to-fast-properties": "^2.0.0" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
| @@ -4584,8 +4579,7 @@ | |||||||
|     }, |     }, | ||||||
|     "node_modules/ansi-styles": { |     "node_modules/ansi-styles": { | ||||||
|       "version": "3.2.1", |       "version": "3.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", |       "license": "MIT", | ||||||
|       "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", |  | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "color-convert": "^1.9.0" |         "color-convert": "^1.9.0" | ||||||
|       }, |       }, | ||||||
| @@ -4760,9 +4754,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/axios": { |     "node_modules/axios": { | ||||||
|       "version": "1.6.1", |       "version": "1.3.5", | ||||||
|       "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", |       "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.5.tgz", | ||||||
|       "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", |       "integrity": "sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw==", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "follow-redirects": "^1.15.0", |         "follow-redirects": "^1.15.0", | ||||||
|         "form-data": "^4.0.0", |         "form-data": "^4.0.0", | ||||||
| @@ -5011,8 +5005,7 @@ | |||||||
|     }, |     }, | ||||||
|     "node_modules/chalk": { |     "node_modules/chalk": { | ||||||
|       "version": "2.4.2", |       "version": "2.4.2", | ||||||
|       "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", |       "license": "MIT", | ||||||
|       "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", |  | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "ansi-styles": "^3.2.1", |         "ansi-styles": "^3.2.1", | ||||||
|         "escape-string-regexp": "^1.0.5", |         "escape-string-regexp": "^1.0.5", | ||||||
| @@ -5024,8 +5017,7 @@ | |||||||
|     }, |     }, | ||||||
|     "node_modules/chalk/node_modules/escape-string-regexp": { |     "node_modules/chalk/node_modules/escape-string-regexp": { | ||||||
|       "version": "1.0.5", |       "version": "1.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", |       "license": "MIT", | ||||||
|       "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", |  | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=0.8.0" |         "node": ">=0.8.0" | ||||||
|       } |       } | ||||||
| @@ -5116,16 +5108,14 @@ | |||||||
|     }, |     }, | ||||||
|     "node_modules/color-convert": { |     "node_modules/color-convert": { | ||||||
|       "version": "1.9.3", |       "version": "1.9.3", | ||||||
|       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", |       "license": "MIT", | ||||||
|       "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", |  | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "color-name": "1.1.3" |         "color-name": "1.1.3" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/color-name": { |     "node_modules/color-name": { | ||||||
|       "version": "1.1.3", |       "version": "1.1.3", | ||||||
|       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", |       "license": "MIT" | ||||||
|       "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" |  | ||||||
|     }, |     }, | ||||||
|     "node_modules/colorette": { |     "node_modules/colorette": { | ||||||
|       "version": "2.0.20", |       "version": "2.0.20", | ||||||
| @@ -6779,8 +6769,7 @@ | |||||||
|     }, |     }, | ||||||
|     "node_modules/has-flag": { |     "node_modules/has-flag": { | ||||||
|       "version": "3.0.0", |       "version": "3.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", |       "license": "MIT", | ||||||
|       "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", |  | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=4" |         "node": ">=4" | ||||||
|       } |       } | ||||||
| @@ -8449,9 +8438,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/postcss": { |     "node_modules/postcss": { | ||||||
|       "version": "8.4.31", |       "version": "8.4.28", | ||||||
|       "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", |       "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", | ||||||
|       "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", |       "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", | ||||||
|       "funding": [ |       "funding": [ | ||||||
|         { |         { | ||||||
|           "type": "opencollective", |           "type": "opencollective", | ||||||
| @@ -9676,8 +9665,7 @@ | |||||||
|     }, |     }, | ||||||
|     "node_modules/supports-color": { |     "node_modules/supports-color": { | ||||||
|       "version": "5.5.0", |       "version": "5.5.0", | ||||||
|       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", |       "license": "MIT", | ||||||
|       "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", |  | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "has-flag": "^3.0.0" |         "has-flag": "^3.0.0" | ||||||
|       }, |       }, | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "ucentral-client", |   "name": "ucentral-client", | ||||||
|   "version": "3.0.0(1)", |   "version": "2.11.0(7)", | ||||||
|   "description": "", |   "description": "", | ||||||
|   "private": true, |   "private": true, | ||||||
|   "main": "index.tsx", |   "main": "index.tsx", | ||||||
|   | |||||||
| @@ -269,7 +269,6 @@ | |||||||
| 		"map": "Karte", | 		"map": "Karte", | ||||||
| 		"max": "Max", | 		"max": "Max", | ||||||
| 		"min": "MINDEST", | 		"min": "MINDEST", | ||||||
| 		"miscellaneous": "Verschiedenes", |  | ||||||
| 		"mode": "Modus", | 		"mode": "Modus", | ||||||
| 		"model": "Modell", | 		"model": "Modell", | ||||||
| 		"modified": "Geändert", | 		"modified": "Geändert", | ||||||
| @@ -738,7 +737,6 @@ | |||||||
| 	"form": { | 	"form": { | ||||||
| 		"captive_web_root_explanation": "Bitte verwenden Sie nur .tar-Dateien (keine komprimierten Dateien wie z. B. .targz)", | 		"captive_web_root_explanation": "Bitte verwenden Sie nur .tar-Dateien (keine komprimierten Dateien wie z. B. .targz)", | ||||||
| 		"certificate_file_explanation": "Bitte verwenden Sie eine .pem-Datei, die mit „-----BEGIN CERTIFICATE-----“ beginnt und mit „-----END CERTIFICATE-----“ endet.", | 		"certificate_file_explanation": "Bitte verwenden Sie eine .pem-Datei, die mit „-----BEGIN CERTIFICATE-----“ beginnt und mit „-----END CERTIFICATE-----“ endet.", | ||||||
| 		"invalid_alphanumeric_with_dash": "Akzeptierte Zeichen. sind nur alphanumerisch (Buchstaben & Zahlen)", |  | ||||||
| 		"invalid_cidr": "Ungültige CIDR-IPv4-Adresse. Beispiel: 192.168.0.1/12", | 		"invalid_cidr": "Ungültige CIDR-IPv4-Adresse. Beispiel: 192.168.0.1/12", | ||||||
| 		"invalid_email": "Ungültige E-Mail", | 		"invalid_email": "Ungültige E-Mail", | ||||||
| 		"invalid_file_content": "Ungültiger Dateiinhalt, bitte bestätigen Sie, dass es sich um ein gültiges Format handelt", | 		"invalid_file_content": "Ungültiger Dateiinhalt, bitte bestätigen Sie, dass es sich um ein gültiges Format handelt", | ||||||
| @@ -765,11 +763,7 @@ | |||||||
| 		"invalid_static_ipv4_e": "Ungültige Adresse, dieser Bereich ist für Experimente reserviert (Klasse E). Das erste Oktett sollte 223 oder niedriger sein", | 		"invalid_static_ipv4_e": "Ungültige Adresse, dieser Bereich ist für Experimente reserviert (Klasse E). Das erste Oktett sollte 223 oder niedriger sein", | ||||||
| 		"invalid_third_party": "Ungültige Drittanbieter-JSON-Zeichenfolge. Bitte bestätigen Sie, dass Ihr Wert ein gültiges JSON ist", | 		"invalid_third_party": "Ungültige Drittanbieter-JSON-Zeichenfolge. Bitte bestätigen Sie, dass Ihr Wert ein gültiges JSON ist", | ||||||
| 		"key_file_explanation": "Bitte verwenden Sie eine .pem-Datei, die mit „-----BEGIN PRIVATE KEY-----“ beginnt und mit „-----END PRIVATE KEY-----“ endet.", | 		"key_file_explanation": "Bitte verwenden Sie eine .pem-Datei, die mit „-----BEGIN PRIVATE KEY-----“ beginnt und mit „-----END PRIVATE KEY-----“ endet.", | ||||||
| 		"max_length": "Maximale Länge von {{max}} Zeichen.", |  | ||||||
| 		"max_value": "Maximalwert von {{max}}", |  | ||||||
| 		"min_length": "Mindestlänge von {{min}} Zeichen.", |  | ||||||
| 		"min_max_string": "Der Wert muss eine Länge zwischen {{min}} (einschließlich) und {{max}} (einschließlich) haben.", | 		"min_max_string": "Der Wert muss eine Länge zwischen {{min}} (einschließlich) und {{max}} (einschließlich) haben.", | ||||||
| 		"min_value": "Mindestwert von {{min}}", |  | ||||||
| 		"missing_interface_upstream": "Sie müssen mindestens eine Upstream-Schnittstelle haben. Im Moment sind alle Ihre Schnittstellen nachgelagert", | 		"missing_interface_upstream": "Sie müssen mindestens eine Upstream-Schnittstelle haben. Im Moment sind alle Ihre Schnittstellen nachgelagert", | ||||||
| 		"new_email_to_notify": "Neue E-Mail zur Benachrichtigung", | 		"new_email_to_notify": "Neue E-Mail zur Benachrichtigung", | ||||||
| 		"new_phone_to_notify": "Neues Telefon zu benachrichtigen", | 		"new_phone_to_notify": "Neues Telefon zu benachrichtigen", | ||||||
| @@ -911,11 +905,6 @@ | |||||||
| 		"one": "Benachrichtigung", | 		"one": "Benachrichtigung", | ||||||
| 		"other": "Benachrichtigungen" | 		"other": "Benachrichtigungen" | ||||||
| 	}, | 	}, | ||||||
| 	"openroaming": { |  | ||||||
| 		"pool_strategy": "Pool-Strategie", |  | ||||||
| 		"radius_endpoint_one": "Radiusendpunkt", |  | ||||||
| 		"radius_endpoint_other": "Radiusendpunkte" |  | ||||||
| 	}, |  | ||||||
| 	"operator": { | 	"operator": { | ||||||
| 		"delete_explanation": "Möchten Sie diesen Operator wirklich löschen? Dieser Vorgang ist nicht umkehrbar", | 		"delete_explanation": "Möchten Sie diesen Operator wirklich löschen? Dieser Vorgang ist nicht umkehrbar", | ||||||
| 		"delete_operator": "Betreiber löschen", | 		"delete_operator": "Betreiber löschen", | ||||||
| @@ -981,27 +970,6 @@ | |||||||
| 		"title": "Beschränkungen", | 		"title": "Beschränkungen", | ||||||
| 		"tty": "TTY-Zugriff" | 		"tty": "TTY-Zugriff" | ||||||
| 	}, | 	}, | ||||||
| 	"roaming": { |  | ||||||
| 		"account_created": "Neues Konto erstellt!", |  | ||||||
| 		"account_deleted": "Konto gelöscht!", |  | ||||||
| 		"account_one": "Konto", |  | ||||||
| 		"account_other": "Konten", |  | ||||||
| 		"certificate_deleted": "Zertifikat gelöscht!", |  | ||||||
| 		"certificate_one": "Zertifikat", |  | ||||||
| 		"certificate_other": "Zertifikate", |  | ||||||
| 		"city": "Stadt", |  | ||||||
| 		"common_name": "Gemeinsamen Namen", |  | ||||||
| 		"country": "Land", |  | ||||||
| 		"global_reach": "Globale Reichweite", |  | ||||||
| 		"global_reach_account_id": "Konto-ID", |  | ||||||
| 		"invalid_certificate": "Ungültiges Zertifikat", |  | ||||||
| 		"invalid_key": "Ungültiger privater Schlüssel", |  | ||||||
| 		"location_details_title": "Ort", |  | ||||||
| 		"organization": "Organisation", |  | ||||||
| 		"private_key": "Privat Schlüssel", |  | ||||||
| 		"province": "Provinz", |  | ||||||
| 		"state": "Zustand" |  | ||||||
| 	}, |  | ||||||
| 	"rrm": { | 	"rrm": { | ||||||
| 		"algorithm": "Algorithmus", | 		"algorithm": "Algorithmus", | ||||||
| 		"algorithm_other": "Algorithmen", | 		"algorithm_other": "Algorithmen", | ||||||
| @@ -1123,7 +1091,6 @@ | |||||||
| 		"title": "Abonnenten" | 		"title": "Abonnenten" | ||||||
| 	}, | 	}, | ||||||
| 	"system": { | 	"system": { | ||||||
| 		"advanced": "Erweitert", |  | ||||||
| 		"backend_logs": "Back-End-Protokolle", | 		"backend_logs": "Back-End-Protokolle", | ||||||
| 		"configuration": "Aufbau", | 		"configuration": "Aufbau", | ||||||
| 		"could_not_retrieve": "Fehler: {{name}} Systeminformationen konnten nicht abgerufen werden", | 		"could_not_retrieve": "Fehler: {{name}} Systeminformationen konnten nicht abgerufen werden", | ||||||
|   | |||||||
| @@ -269,7 +269,6 @@ | |||||||
| 		"map": "Map", | 		"map": "Map", | ||||||
| 		"max": "Max", | 		"max": "Max", | ||||||
| 		"min": "Min", | 		"min": "Min", | ||||||
| 		"miscellaneous": "Miscellaneous", |  | ||||||
| 		"mode": "Mode", | 		"mode": "Mode", | ||||||
| 		"model": "Model", | 		"model": "Model", | ||||||
| 		"modified": "Modified", | 		"modified": "Modified", | ||||||
| @@ -738,7 +737,6 @@ | |||||||
| 	"form": { | 	"form": { | ||||||
| 		"captive_web_root_explanation": "Please use .tar files only (no compressed files like .targz, for example)", | 		"captive_web_root_explanation": "Please use .tar files only (no compressed files like .targz, for example)", | ||||||
| 		"certificate_file_explanation": "Please use a .pem file that starts with \"-----BEGIN CERTIFICATE-----\" and ends with \"-----END CERTIFICATE-----\"", | 		"certificate_file_explanation": "Please use a .pem file that starts with \"-----BEGIN CERTIFICATE-----\" and ends with \"-----END CERTIFICATE-----\"", | ||||||
| 		"invalid_alphanumeric_with_dash": "Accepted chars. are only alphanumeric (letters & numbers)", |  | ||||||
| 		"invalid_cidr": "Invalid CIDR IPv4 address. Example: 192.168.0.1/12", | 		"invalid_cidr": "Invalid CIDR IPv4 address. Example: 192.168.0.1/12", | ||||||
| 		"invalid_email": "Invalid Email", | 		"invalid_email": "Invalid Email", | ||||||
| 		"invalid_file_content": "Invalid file content, please confirm that it is of the valid format", | 		"invalid_file_content": "Invalid file content, please confirm that it is of the valid format", | ||||||
| @@ -765,11 +763,7 @@ | |||||||
| 		"invalid_static_ipv4_e": "Invalid address, this range reserved for experiments (class E). The first octet should be 223 or lower", | 		"invalid_static_ipv4_e": "Invalid address, this range reserved for experiments (class E). The first octet should be 223 or lower", | ||||||
| 		"invalid_third_party": "Invalid Third Party JSON string. Please confirm that your value is a valid JSON", | 		"invalid_third_party": "Invalid Third Party JSON string. Please confirm that your value is a valid JSON", | ||||||
| 		"key_file_explanation": "Please use a .pem file that starts with \"-----BEGIN PRIVATE KEY-----\" and ends with \"-----END PRIVATE KEY-----\"", | 		"key_file_explanation": "Please use a .pem file that starts with \"-----BEGIN PRIVATE KEY-----\" and ends with \"-----END PRIVATE KEY-----\"", | ||||||
| 		"max_length": "Maximum length of {{max}} chars.", |  | ||||||
| 		"max_value": "Maximum value of {{max}}", |  | ||||||
| 		"min_length": "Minimum length of {{min}} chars.", |  | ||||||
| 		"min_max_string": "Value needs to be of a length between {{min}} (inclusive) and {{max}} (inclusive)", | 		"min_max_string": "Value needs to be of a length between {{min}} (inclusive) and {{max}} (inclusive)", | ||||||
| 		"min_value": "Minimum value of {{min}}", |  | ||||||
| 		"missing_interface_upstream": "You need to have at least one upstream interface. At the moment, all your interfaces are downstream", | 		"missing_interface_upstream": "You need to have at least one upstream interface. At the moment, all your interfaces are downstream", | ||||||
| 		"new_email_to_notify": "New email to notify", | 		"new_email_to_notify": "New email to notify", | ||||||
| 		"new_phone_to_notify": "New phone to notify", | 		"new_phone_to_notify": "New phone to notify", | ||||||
| @@ -911,11 +905,6 @@ | |||||||
| 		"one": "Notification", | 		"one": "Notification", | ||||||
| 		"other": "Notifications" | 		"other": "Notifications" | ||||||
| 	}, | 	}, | ||||||
| 	"openroaming": { |  | ||||||
| 		"pool_strategy": "Pool Strategy", |  | ||||||
| 		"radius_endpoint_one": "Radius Endpoint", |  | ||||||
| 		"radius_endpoint_other": "Radius Endpoints" |  | ||||||
| 	}, |  | ||||||
| 	"operator": { | 	"operator": { | ||||||
| 		"delete_explanation": "Are you sure you want to delete this operator? This operation is not reversible", | 		"delete_explanation": "Are you sure you want to delete this operator? This operation is not reversible", | ||||||
| 		"delete_operator": "Delete Operator", | 		"delete_operator": "Delete Operator", | ||||||
| @@ -981,27 +970,6 @@ | |||||||
| 		"title": "Restrictions", | 		"title": "Restrictions", | ||||||
| 		"tty": "TTY Access" | 		"tty": "TTY Access" | ||||||
| 	}, | 	}, | ||||||
| 	"roaming": { |  | ||||||
| 		"account_created": "New account created!", |  | ||||||
| 		"account_deleted": "Deleted account!", |  | ||||||
| 		"account_one": "Account", |  | ||||||
| 		"account_other": "Accounts", |  | ||||||
| 		"certificate_deleted": "Deleted certificate!", |  | ||||||
| 		"certificate_one": "Certificate", |  | ||||||
| 		"certificate_other": "Certificates", |  | ||||||
| 		"city": "City", |  | ||||||
| 		"common_name": "Common Name", |  | ||||||
| 		"country": "Country", |  | ||||||
| 		"global_reach": "GlobalReach", |  | ||||||
| 		"global_reach_account_id": " Account ID", |  | ||||||
| 		"invalid_certificate": "Invalid certificate", |  | ||||||
| 		"invalid_key": "Invalid private key", |  | ||||||
| 		"location_details_title": "Location", |  | ||||||
| 		"organization": "Organization", |  | ||||||
| 		"private_key": "Private Key", |  | ||||||
| 		"province": "Province", |  | ||||||
| 		"state": "State" |  | ||||||
| 	}, |  | ||||||
| 	"rrm": { | 	"rrm": { | ||||||
| 		"algorithm": "Algorithm", | 		"algorithm": "Algorithm", | ||||||
| 		"algorithm_other": "Algorithms", | 		"algorithm_other": "Algorithms", | ||||||
| @@ -1123,7 +1091,6 @@ | |||||||
| 		"title": "Subscribers" | 		"title": "Subscribers" | ||||||
| 	}, | 	}, | ||||||
| 	"system": { | 	"system": { | ||||||
| 		"advanced": "Advanced", |  | ||||||
| 		"backend_logs": "Back-End Logs", | 		"backend_logs": "Back-End Logs", | ||||||
| 		"configuration": "Configuration", | 		"configuration": "Configuration", | ||||||
| 		"could_not_retrieve": "Error: could not retrieve {{name}} system information", | 		"could_not_retrieve": "Error: could not retrieve {{name}} system information", | ||||||
|   | |||||||
| @@ -269,7 +269,6 @@ | |||||||
| 		"map": "Mapa", | 		"map": "Mapa", | ||||||
| 		"max": "Max", | 		"max": "Max", | ||||||
| 		"min": "Min", | 		"min": "Min", | ||||||
| 		"miscellaneous": "Diverso", |  | ||||||
| 		"mode": "Modo", | 		"mode": "Modo", | ||||||
| 		"model": "Modelo", | 		"model": "Modelo", | ||||||
| 		"modified": "Modificado", | 		"modified": "Modificado", | ||||||
| @@ -738,7 +737,6 @@ | |||||||
| 	"form": { | 	"form": { | ||||||
| 		"captive_web_root_explanation": "Utilice únicamente archivos .tar (no archivos comprimidos como .targz, por ejemplo)", | 		"captive_web_root_explanation": "Utilice únicamente archivos .tar (no archivos comprimidos como .targz, por ejemplo)", | ||||||
| 		"certificate_file_explanation": "Utilice un archivo .pem que comience con \"-----BEGIN CERTIFICATE-----\" y termine con \"-----END CERTIFICATE-----\"", | 		"certificate_file_explanation": "Utilice un archivo .pem que comience con \"-----BEGIN CERTIFICATE-----\" y termine con \"-----END CERTIFICATE-----\"", | ||||||
| 		"invalid_alphanumeric_with_dash": "Caracteres aceptados. son solo alfanuméricos (letras y números)", |  | ||||||
| 		"invalid_cidr": "Dirección IPv4 CIDR no válida. Ejemplo: 192.168.0.1/12", | 		"invalid_cidr": "Dirección IPv4 CIDR no válida. Ejemplo: 192.168.0.1/12", | ||||||
| 		"invalid_email": "Email inválido", | 		"invalid_email": "Email inválido", | ||||||
| 		"invalid_file_content": "Contenido de archivo no válido, confirme que tiene un formato válido", | 		"invalid_file_content": "Contenido de archivo no válido, confirme que tiene un formato válido", | ||||||
| @@ -765,11 +763,7 @@ | |||||||
| 		"invalid_static_ipv4_e": "Dirección no válida, este rango reservado para experimentos (clase E). El primer octeto debe ser 223 o inferior", | 		"invalid_static_ipv4_e": "Dirección no válida, este rango reservado para experimentos (clase E). El primer octeto debe ser 223 o inferior", | ||||||
| 		"invalid_third_party": "Cadena JSON de terceros no válida. Confirme que su valor es un JSON válido", | 		"invalid_third_party": "Cadena JSON de terceros no válida. Confirme que su valor es un JSON válido", | ||||||
| 		"key_file_explanation": "Utilice un archivo .pem que comience con \"-----BEGIN PRIVATE KEY-----\" y termine con \"-----END PRIVATE KEY-----\"", | 		"key_file_explanation": "Utilice un archivo .pem que comience con \"-----BEGIN PRIVATE KEY-----\" y termine con \"-----END PRIVATE KEY-----\"", | ||||||
| 		"max_length": "Longitud máxima de {{max}} caracteres.", |  | ||||||
| 		"max_value": "Valor máximo de {{max}}", |  | ||||||
| 		"min_length": "Longitud mínima de {{min}} caracteres.", |  | ||||||
| 		"min_max_string": "El valor debe tener una longitud entre {{min}} (inclusive) y {{max}} (inclusive)", | 		"min_max_string": "El valor debe tener una longitud entre {{min}} (inclusive) y {{max}} (inclusive)", | ||||||
| 		"min_value": "Valor mínimo de {{min}}", |  | ||||||
| 		"missing_interface_upstream": "Debe tener al menos una interfaz ascendente. Por el momento, todas sus interfaces están en sentido descendente", | 		"missing_interface_upstream": "Debe tener al menos una interfaz ascendente. Por el momento, todas sus interfaces están en sentido descendente", | ||||||
| 		"new_email_to_notify": "Nuevo correo electrónico para notificar", | 		"new_email_to_notify": "Nuevo correo electrónico para notificar", | ||||||
| 		"new_phone_to_notify": "Nuevo teléfono para avisar", | 		"new_phone_to_notify": "Nuevo teléfono para avisar", | ||||||
| @@ -911,11 +905,6 @@ | |||||||
| 		"one": "Notificación", | 		"one": "Notificación", | ||||||
| 		"other": "Notificaciones" | 		"other": "Notificaciones" | ||||||
| 	}, | 	}, | ||||||
| 	"openroaming": { |  | ||||||
| 		"pool_strategy": "Estrategia de piscina", |  | ||||||
| 		"radius_endpoint_one": "Punto final del radio", |  | ||||||
| 		"radius_endpoint_other": "Puntos finales de radio" |  | ||||||
| 	}, |  | ||||||
| 	"operator": { | 	"operator": { | ||||||
| 		"delete_explanation": "¿Está seguro de que desea eliminar este operador? Esta operación no es reversible.", | 		"delete_explanation": "¿Está seguro de que desea eliminar este operador? Esta operación no es reversible.", | ||||||
| 		"delete_operator": "Eliminar operador", | 		"delete_operator": "Eliminar operador", | ||||||
| @@ -981,27 +970,6 @@ | |||||||
| 		"title": "Las restricciones", | 		"title": "Las restricciones", | ||||||
| 		"tty": "Acceso TTY" | 		"tty": "Acceso TTY" | ||||||
| 	}, | 	}, | ||||||
| 	"roaming": { |  | ||||||
| 		"account_created": "¡Nueva cuenta creada!", |  | ||||||
| 		"account_deleted": "¡Cuenta eliminada!", |  | ||||||
| 		"account_one": "Cuenta", |  | ||||||
| 		"account_other": "Cuentas", |  | ||||||
| 		"certificate_deleted": "Certificado eliminado!", |  | ||||||
| 		"certificate_one": "Certificado", |  | ||||||
| 		"certificate_other": "Certificados", |  | ||||||
| 		"city": "ciudad", |  | ||||||
| 		"common_name": "Nombre común", |  | ||||||
| 		"country": "País", |  | ||||||
| 		"global_reach": "Alcance global", |  | ||||||
| 		"global_reach_account_id": "ID de cuenta ", |  | ||||||
| 		"invalid_certificate": "Certificado inválido", |  | ||||||
| 		"invalid_key": "Clave privada no válida", |  | ||||||
| 		"location_details_title": "Ubicación", |  | ||||||
| 		"organization": "Organización", |  | ||||||
| 		"private_key": "Llave privada", |  | ||||||
| 		"province": "Provincia", |  | ||||||
| 		"state": "Estado" |  | ||||||
| 	}, |  | ||||||
| 	"rrm": { | 	"rrm": { | ||||||
| 		"algorithm": "Algoritmo", | 		"algorithm": "Algoritmo", | ||||||
| 		"algorithm_other": "Algoritmos", | 		"algorithm_other": "Algoritmos", | ||||||
| @@ -1123,7 +1091,6 @@ | |||||||
| 		"title": "Suscriptores" | 		"title": "Suscriptores" | ||||||
| 	}, | 	}, | ||||||
| 	"system": { | 	"system": { | ||||||
| 		"advanced": "Avanzado", |  | ||||||
| 		"backend_logs": "Registros de back-end", | 		"backend_logs": "Registros de back-end", | ||||||
| 		"configuration": "Configuración", | 		"configuration": "Configuración", | ||||||
| 		"could_not_retrieve": "Error: no se pudo recuperar la información del sistema {{name}} ", | 		"could_not_retrieve": "Error: no se pudo recuperar la información del sistema {{name}} ", | ||||||
|   | |||||||
| @@ -269,7 +269,6 @@ | |||||||
| 		"map": "Carte", | 		"map": "Carte", | ||||||
| 		"max": "Max", | 		"max": "Max", | ||||||
| 		"min": "Min", | 		"min": "Min", | ||||||
| 		"miscellaneous": "Divers", |  | ||||||
| 		"mode": "Mode", | 		"mode": "Mode", | ||||||
| 		"model": "Modèle", | 		"model": "Modèle", | ||||||
| 		"modified": "Modifié", | 		"modified": "Modifié", | ||||||
| @@ -738,7 +737,6 @@ | |||||||
| 	"form": { | 	"form": { | ||||||
| 		"captive_web_root_explanation": "Veuillez utiliser uniquement des fichiers .tar (pas de fichiers compressés comme .targz, par exemple)", | 		"captive_web_root_explanation": "Veuillez utiliser uniquement des fichiers .tar (pas de fichiers compressés comme .targz, par exemple)", | ||||||
| 		"certificate_file_explanation": "Veuillez utiliser un fichier .pem qui commence par \"-----BEGIN CERTIFICATE-----\" et se termine par \"-----END CERTIFICATE-----\"", | 		"certificate_file_explanation": "Veuillez utiliser un fichier .pem qui commence par \"-----BEGIN CERTIFICATE-----\" et se termine par \"-----END CERTIFICATE-----\"", | ||||||
| 		"invalid_alphanumeric_with_dash": "Caractères acceptés. sont uniquement alphanumériques (lettres et chiffres)", |  | ||||||
| 		"invalid_cidr": "Adresse IPv4 CIDR non valide. Exemple : 192.168.0.1/12", | 		"invalid_cidr": "Adresse IPv4 CIDR non valide. Exemple : 192.168.0.1/12", | ||||||
| 		"invalid_email": "Email Invalide", | 		"invalid_email": "Email Invalide", | ||||||
| 		"invalid_file_content": "Contenu de fichier non valide, veuillez confirmer qu'il est au format valide", | 		"invalid_file_content": "Contenu de fichier non valide, veuillez confirmer qu'il est au format valide", | ||||||
| @@ -765,11 +763,7 @@ | |||||||
| 		"invalid_static_ipv4_e": "Adresse invalide, cette plage est réservée aux expérimentations (classe E). Le premier octet doit être 223 ou moins", | 		"invalid_static_ipv4_e": "Adresse invalide, cette plage est réservée aux expérimentations (classe E). Le premier octet doit être 223 ou moins", | ||||||
| 		"invalid_third_party": "Chaîne JSON tierce non valide. Veuillez confirmer que votre valeur est un JSON valide", | 		"invalid_third_party": "Chaîne JSON tierce non valide. Veuillez confirmer que votre valeur est un JSON valide", | ||||||
| 		"key_file_explanation": "Veuillez utiliser un fichier .pem qui commence par \"-----BEGIN PRIVATE KEY-----\" et se termine par \"-----END PRIVATE KEY-----\"", | 		"key_file_explanation": "Veuillez utiliser un fichier .pem qui commence par \"-----BEGIN PRIVATE KEY-----\" et se termine par \"-----END PRIVATE KEY-----\"", | ||||||
| 		"max_length": "Longueur maximale de {{max}}  caractères.", |  | ||||||
| 		"max_value": "Valeur maximale de  {{max}}", |  | ||||||
| 		"min_length": "Longueur minimale de {{min}}  caractères.", |  | ||||||
| 		"min_max_string": "La valeur doit être d'une longueur comprise entre {{min}} (inclus) et {{max}} (inclus)", | 		"min_max_string": "La valeur doit être d'une longueur comprise entre {{min}} (inclus) et {{max}} (inclus)", | ||||||
| 		"min_value": "Valeur minimale de  {{min}}", |  | ||||||
| 		"missing_interface_upstream": "Vous devez avoir au moins une interface en amont. Pour le moment, toutes vos interfaces sont en aval", | 		"missing_interface_upstream": "Vous devez avoir au moins une interface en amont. Pour le moment, toutes vos interfaces sont en aval", | ||||||
| 		"new_email_to_notify": "Nouvel e-mail à notifier", | 		"new_email_to_notify": "Nouvel e-mail à notifier", | ||||||
| 		"new_phone_to_notify": "Nouveau téléphone à notifier", | 		"new_phone_to_notify": "Nouveau téléphone à notifier", | ||||||
| @@ -911,11 +905,6 @@ | |||||||
| 		"one": "Notification", | 		"one": "Notification", | ||||||
| 		"other": "Les notifications" | 		"other": "Les notifications" | ||||||
| 	}, | 	}, | ||||||
| 	"openroaming": { |  | ||||||
| 		"pool_strategy": "Stratégie de pool", |  | ||||||
| 		"radius_endpoint_one": "Point final de rayon", |  | ||||||
| 		"radius_endpoint_other": "Points de terminaison du rayon" |  | ||||||
| 	}, |  | ||||||
| 	"operator": { | 	"operator": { | ||||||
| 		"delete_explanation": "Voulez-vous vraiment supprimer cet opérateur ? Cette opération n'est pas réversible", | 		"delete_explanation": "Voulez-vous vraiment supprimer cet opérateur ? Cette opération n'est pas réversible", | ||||||
| 		"delete_operator": "Supprimer l'opérateur", | 		"delete_operator": "Supprimer l'opérateur", | ||||||
| @@ -981,27 +970,6 @@ | |||||||
| 		"title": "Restrictions", | 		"title": "Restrictions", | ||||||
| 		"tty": "Accès ATS" | 		"tty": "Accès ATS" | ||||||
| 	}, | 	}, | ||||||
| 	"roaming": { |  | ||||||
| 		"account_created": "Nouveau compte créé !", |  | ||||||
| 		"account_deleted": "Compte supprimé !", |  | ||||||
| 		"account_one": "Compte", |  | ||||||
| 		"account_other": "Comptes", |  | ||||||
| 		"certificate_deleted": "Certificat supprimé !", |  | ||||||
| 		"certificate_one": "Certificat", |  | ||||||
| 		"certificate_other": "Certificats", |  | ||||||
| 		"city": "Ville", |  | ||||||
| 		"common_name": "Nom commun", |  | ||||||
| 		"country": "Pays", |  | ||||||
| 		"global_reach": "Portée mondiale", |  | ||||||
| 		"global_reach_account_id": "ID de compte ", |  | ||||||
| 		"invalid_certificate": "certificat invalide", |  | ||||||
| 		"invalid_key": "Clé privée invalide", |  | ||||||
| 		"location_details_title": "Emplacement", |  | ||||||
| 		"organization": "Organisation", |  | ||||||
| 		"private_key": "Clé privée", |  | ||||||
| 		"province": "province", |  | ||||||
| 		"state": "Etat" |  | ||||||
| 	}, |  | ||||||
| 	"rrm": { | 	"rrm": { | ||||||
| 		"algorithm": "Algorithme", | 		"algorithm": "Algorithme", | ||||||
| 		"algorithm_other": "Algorithmes", | 		"algorithm_other": "Algorithmes", | ||||||
| @@ -1123,7 +1091,6 @@ | |||||||
| 		"title": "Les abonnés" | 		"title": "Les abonnés" | ||||||
| 	}, | 	}, | ||||||
| 	"system": { | 	"system": { | ||||||
| 		"advanced": "Avancée", |  | ||||||
| 		"backend_logs": "Journaux principaux", | 		"backend_logs": "Journaux principaux", | ||||||
| 		"configuration": "Configuration", | 		"configuration": "Configuration", | ||||||
| 		"could_not_retrieve": "Erreur : impossible de récupérer les informations système {{name}} ", | 		"could_not_retrieve": "Erreur : impossible de récupérer les informations système {{name}} ", | ||||||
|   | |||||||
| @@ -269,7 +269,6 @@ | |||||||
| 		"map": "Mapa", | 		"map": "Mapa", | ||||||
| 		"max": "máximo", | 		"max": "máximo", | ||||||
| 		"min": "minuto", | 		"min": "minuto", | ||||||
| 		"miscellaneous": "Diversos", |  | ||||||
| 		"mode": "Modo", | 		"mode": "Modo", | ||||||
| 		"model": "Modelo", | 		"model": "Modelo", | ||||||
| 		"modified": "Modificado", | 		"modified": "Modificado", | ||||||
| @@ -738,7 +737,6 @@ | |||||||
| 	"form": { | 	"form": { | ||||||
| 		"captive_web_root_explanation": "Por favor, use apenas arquivos .tar (sem arquivos compactados como .targz, por exemplo)", | 		"captive_web_root_explanation": "Por favor, use apenas arquivos .tar (sem arquivos compactados como .targz, por exemplo)", | ||||||
| 		"certificate_file_explanation": "Use um arquivo .pem que comece com \"-----BEGIN CERTIFICATE-----\" e termine com \"-----END CERTIFICATE-----\"", | 		"certificate_file_explanation": "Use um arquivo .pem que comece com \"-----BEGIN CERTIFICATE-----\" e termine com \"-----END CERTIFICATE-----\"", | ||||||
| 		"invalid_alphanumeric_with_dash": "Caracteres aceitos. são apenas alfanuméricos (letras e números)", |  | ||||||
| 		"invalid_cidr": "Endereço CIDR IPv4 inválido. Exemplo: 192.168.0.1/12", | 		"invalid_cidr": "Endereço CIDR IPv4 inválido. Exemplo: 192.168.0.1/12", | ||||||
| 		"invalid_email": "E-mail inválido", | 		"invalid_email": "E-mail inválido", | ||||||
| 		"invalid_file_content": "Conteúdo de arquivo inválido. Confirme se está no formato válido", | 		"invalid_file_content": "Conteúdo de arquivo inválido. Confirme se está no formato válido", | ||||||
| @@ -765,11 +763,7 @@ | |||||||
| 		"invalid_static_ipv4_e": "Endereço inválido, este intervalo é reservado para experimentos (classe E). O primeiro octeto deve ser 223 ou inferior", | 		"invalid_static_ipv4_e": "Endereço inválido, este intervalo é reservado para experimentos (classe E). O primeiro octeto deve ser 223 ou inferior", | ||||||
| 		"invalid_third_party": "String JSON de terceiros inválida. Confirme se seu valor é um JSON válido", | 		"invalid_third_party": "String JSON de terceiros inválida. Confirme se seu valor é um JSON válido", | ||||||
| 		"key_file_explanation": "Use um arquivo .pem que comece com \"-----BEGIN PRIVATE KEY-----\" e termine com \"-----END PRIVATE KEY-----\"", | 		"key_file_explanation": "Use um arquivo .pem que comece com \"-----BEGIN PRIVATE KEY-----\" e termine com \"-----END PRIVATE KEY-----\"", | ||||||
| 		"max_length": "Comprimento máximo de {{max}} caracteres.", |  | ||||||
| 		"max_value": "Valor máximo de {{max}}", |  | ||||||
| 		"min_length": "Comprimento mínimo de {{min}} caracteres.", |  | ||||||
| 		"min_max_string": "O valor precisa ter um comprimento entre {{min}} (inclusive) e {{max}} (inclusive)", | 		"min_max_string": "O valor precisa ter um comprimento entre {{min}} (inclusive) e {{max}} (inclusive)", | ||||||
| 		"min_value": "Valor mínimo de {{min}}", |  | ||||||
| 		"missing_interface_upstream": "Você precisa ter pelo menos uma interface upstream. No momento, todas as suas interfaces estão downstream", | 		"missing_interface_upstream": "Você precisa ter pelo menos uma interface upstream. No momento, todas as suas interfaces estão downstream", | ||||||
| 		"new_email_to_notify": "Novo e-mail para notificar", | 		"new_email_to_notify": "Novo e-mail para notificar", | ||||||
| 		"new_phone_to_notify": "Novo telefone para notificar", | 		"new_phone_to_notify": "Novo telefone para notificar", | ||||||
| @@ -911,11 +905,6 @@ | |||||||
| 		"one": "Notificação", | 		"one": "Notificação", | ||||||
| 		"other": "Notificações" | 		"other": "Notificações" | ||||||
| 	}, | 	}, | ||||||
| 	"openroaming": { |  | ||||||
| 		"pool_strategy": "Estratégia de pool", |  | ||||||
| 		"radius_endpoint_one": "Ponto final do raio", |  | ||||||
| 		"radius_endpoint_other": "Pontos finais de raio" |  | ||||||
| 	}, |  | ||||||
| 	"operator": { | 	"operator": { | ||||||
| 		"delete_explanation": "Tem certeza de que deseja excluir este operador? Esta operação não é reversível", | 		"delete_explanation": "Tem certeza de que deseja excluir este operador? Esta operação não é reversível", | ||||||
| 		"delete_operator": "Excluir operador", | 		"delete_operator": "Excluir operador", | ||||||
| @@ -981,27 +970,6 @@ | |||||||
| 		"title": "RESTRIÇÕES", | 		"title": "RESTRIÇÕES", | ||||||
| 		"tty": "Acesso TTY" | 		"tty": "Acesso TTY" | ||||||
| 	}, | 	}, | ||||||
| 	"roaming": { |  | ||||||
| 		"account_created": "Nova conta criada!", |  | ||||||
| 		"account_deleted": "Conta excluída!", |  | ||||||
| 		"account_one": "Conta", |  | ||||||
| 		"account_other": "Contas", |  | ||||||
| 		"certificate_deleted": "Certificado excluído!", |  | ||||||
| 		"certificate_one": "Certificado", |  | ||||||
| 		"certificate_other": "Certificados", |  | ||||||
| 		"city": "Cidade", |  | ||||||
| 		"common_name": "Nome comum", |  | ||||||
| 		"country": "País", |  | ||||||
| 		"global_reach": "Alcance global", |  | ||||||
| 		"global_reach_account_id": "ID da conta", |  | ||||||
| 		"invalid_certificate": "Certificado inválido", |  | ||||||
| 		"invalid_key": "Chave privada inválida", |  | ||||||
| 		"location_details_title": "Localização", |  | ||||||
| 		"organization": "Organização", |  | ||||||
| 		"private_key": "Chave privada", |  | ||||||
| 		"province": "província", |  | ||||||
| 		"state": "Estado" |  | ||||||
| 	}, |  | ||||||
| 	"rrm": { | 	"rrm": { | ||||||
| 		"algorithm": "Algoritmo", | 		"algorithm": "Algoritmo", | ||||||
| 		"algorithm_other": "Algoritmos", | 		"algorithm_other": "Algoritmos", | ||||||
| @@ -1123,7 +1091,6 @@ | |||||||
| 		"title": "Inscritos" | 		"title": "Inscritos" | ||||||
| 	}, | 	}, | ||||||
| 	"system": { | 	"system": { | ||||||
| 		"advanced": "Avançado", |  | ||||||
| 		"backend_logs": "Registros de back-end", | 		"backend_logs": "Registros de back-end", | ||||||
| 		"configuration": "Configuração", | 		"configuration": "Configuração", | ||||||
| 		"could_not_retrieve": "Erro: não foi possível recuperar {{name}} informações do sistema", | 		"could_not_retrieve": "Erro: não foi possível recuperar {{name}} informações do sistema", | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								src/@tanstack.react-table.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								src/@tanstack.react-table.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,22 +4,18 @@ import '@tanstack/react-table'; | |||||||
|  |  | ||||||
| declare module '@tanstack/table-core' { | declare module '@tanstack/table-core' { | ||||||
|   interface ColumnMeta<TData extends RowData, TValue> { |   interface ColumnMeta<TData extends RowData, TValue> { | ||||||
|     ref?: React.MutableRefObject<HTMLTableCellElement | null>; |  | ||||||
|     customMinWidth?: string; |  | ||||||
|     anchored?: boolean; |  | ||||||
|     stopPropagation?: boolean; |     stopPropagation?: boolean; | ||||||
|     alwaysShow?: boolean; |     alwaysShow?: boolean; | ||||||
|  |     anchored?: boolean; | ||||||
|     hasPopover?: boolean; |     hasPopover?: boolean; | ||||||
|     customMaxWidth?: string; |     customMaxWidth?: string; | ||||||
|  |     customMinWidth?: string; | ||||||
|     customWidth?: string; |     customWidth?: string; | ||||||
|     isMonospace?: boolean; |     isMonospace?: boolean; | ||||||
|     isCentered?: boolean; |     isCentered?: boolean; | ||||||
|     columnSelectorOptions?: { |     columnSelectorOptions?: { | ||||||
|       label?: string; |       label?: string; | ||||||
|     }; |     }; | ||||||
|     rowContentOptions?: { |  | ||||||
|       style?: React.CSSProperties; |  | ||||||
|     }; |  | ||||||
|     headerOptions?: { |     headerOptions?: { | ||||||
|       tooltip?: string; |       tooltip?: string; | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ export const DataGridCellRow = <TValue extends object>({ | |||||||
|         backgroundColor: hoveredRowBg, |         backgroundColor: hoveredRowBg, | ||||||
|       }} |       }} | ||||||
|       onClick={onClick} |       onClick={onClick} | ||||||
|  |       borderRight="1px solid gray" | ||||||
|     > |     > | ||||||
|       {row.getVisibleCells().map((cell) => ( |       {row.getVisibleCells().map((cell) => ( | ||||||
|         <Td |         <Td | ||||||
| @@ -54,7 +55,6 @@ export const DataGridCellRow = <TValue extends object>({ | |||||||
|               : undefined |               : undefined | ||||||
|           } |           } | ||||||
|           border="0.5px solid gray" |           border="0.5px solid gray" | ||||||
|           style={cell.column.columnDef.meta?.rowContentOptions?.style} |  | ||||||
|         > |         > | ||||||
|           {flexRender(cell.column.columnDef.cell, cell.getContext())} |           {flexRender(cell.column.columnDef.cell, cell.getContext())} | ||||||
|         </Td> |         </Td> | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ export type DataGridHeaderRowProps<TValue extends object> = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| export const DataGridHeaderRow = <TValue extends object>({ headerGroup }: DataGridHeaderRowProps<TValue>) => ( | export const DataGridHeaderRow = <TValue extends object>({ headerGroup }: DataGridHeaderRowProps<TValue>) => ( | ||||||
|   <Tr p={0}> |   <Tr p={0} borderRight="1px solid gray"> | ||||||
|     {headerGroup.headers.map((header) => ( |     {headerGroup.headers.map((header) => ( | ||||||
|       <Th |       <Th | ||||||
|         color="gray.400" |         color="gray.400" | ||||||
|   | |||||||
| @@ -40,16 +40,13 @@ export type DataGridOptions<TValue extends object> = { | |||||||
|   onRowClick?: (row: TValue) => (() => void) | undefined; |   onRowClick?: (row: TValue) => (() => void) | undefined; | ||||||
|   refetch?: () => void; |   refetch?: () => void; | ||||||
|   showAsCard?: boolean; |   showAsCard?: boolean; | ||||||
|   hideTablePreferences?: boolean; |  | ||||||
|   hideTableTitleRow?: boolean; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export type DataGridProps<TValue extends object> = { | export type DataGridProps<TValue extends object> = { | ||||||
|   innerTableKey?: string | number; |  | ||||||
|   controller: UseDataGridReturn; |   controller: UseDataGridReturn; | ||||||
|   columns: DataGridColumn<TValue>[]; |   columns: DataGridColumn<TValue>[]; | ||||||
|   header: { |   header: { | ||||||
|     title: string | React.ReactNode; |     title: string; | ||||||
|     objectListed: string; |     objectListed: string; | ||||||
|     leftContent?: React.ReactNode; |     leftContent?: React.ReactNode; | ||||||
|     addButton?: React.ReactNode; |     addButton?: React.ReactNode; | ||||||
| @@ -61,7 +58,6 @@ export type DataGridProps<TValue extends object> = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| export const DataGrid = <TValue extends object>({ | export const DataGrid = <TValue extends object>({ | ||||||
|   innerTableKey, |  | ||||||
|   controller, |   controller, | ||||||
|   columns, |   columns, | ||||||
|   header, |   header, | ||||||
| @@ -153,20 +149,6 @@ export const DataGrid = <TValue extends object>({ | |||||||
|     ...tableOptions, |     ...tableOptions, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   // If this is a manual DataTable, with a page index that is higher than 0 and higher than the max possible page, we send to index 0 |  | ||||||
|   React.useEffect(() => { |  | ||||||
|     if ( |  | ||||||
|       options.isManual && |  | ||||||
|       !isLoading && |  | ||||||
|       data && |  | ||||||
|       pagination.pageIndex > 0 && |  | ||||||
|       options.count !== undefined && |  | ||||||
|       Math.ceil(options.count / pagination.pageSize) - 1 < pagination.pageIndex |  | ||||||
|     ) { |  | ||||||
|       controller.onPaginationChange({ pageIndex: 0, pageSize: pagination.pageSize }); |  | ||||||
|     } |  | ||||||
|   }, [options.count, isLoading, pagination, data]); |  | ||||||
|  |  | ||||||
|   if (isLoading && !options.showAsCard && data.length === 0) { |   if (isLoading && !options.showAsCard && data.length === 0) { | ||||||
|     return ( |     return ( | ||||||
|       <Center> |       <Center> | ||||||
| @@ -178,29 +160,25 @@ export const DataGrid = <TValue extends object>({ | |||||||
|   return options.showAsCard ? ( |   return options.showAsCard ? ( | ||||||
|     <Card> |     <Card> | ||||||
|       <CardHeader> |       <CardHeader> | ||||||
|         {typeof header.title === 'string' ? ( |  | ||||||
|         <Heading size="md" my="auto" mr={2}> |         <Heading size="md" my="auto" mr={2}> | ||||||
|           {header.title} |           {header.title} | ||||||
|         </Heading> |         </Heading> | ||||||
|         ) : ( |  | ||||||
|           header.title |  | ||||||
|         )} |  | ||||||
|         {header.leftContent} |         {header.leftContent} | ||||||
|         <Spacer /> |         <Spacer /> | ||||||
|         <HStack spacing={2}> |         <HStack spacing={2}> | ||||||
|           {header.otherButtons} |           {header.otherButtons} | ||||||
|           {header.addButton} |           {header.addButton} | ||||||
|           {options.hideTablePreferences ? null : ( |           { | ||||||
|             // @ts-ignore |             // @ts-ignore | ||||||
|             <TableSettingsModal<TValue> controller={controller} columns={columns} /> |             <TableSettingsModal<TValue> controller={controller} columns={columns} /> | ||||||
|           )} |           } | ||||||
|           {options.refetch ? <RefreshButton onClick={options.refetch} isCompact isFetching={isLoading} /> : null} |           {options.refetch ? <RefreshButton onClick={options.refetch} isCompact isFetching={isLoading} /> : null} | ||||||
|         </HStack> |         </HStack> | ||||||
|       </CardHeader> |       </CardHeader> | ||||||
|       <CardBody display="flex" flexDirection="column"> |       <CardBody display="flex" flexDirection="column"> | ||||||
|         <LoadingOverlay isLoading={isLoading}> |         <LoadingOverlay isLoading={isLoading}> | ||||||
|           <TableContainer minH={minimumHeight}> |           <TableContainer minH={minimumHeight}> | ||||||
|             <Table size="small" variant="simple" textColor={textColor} w="100%" fontSize="14px" key={innerTableKey}> |             <Table size="small" variant="simple" textColor={textColor} w="100%" fontSize="14px"> | ||||||
|               <Thead> |               <Thead> | ||||||
|                 {table.getHeaderGroups().map((headerGroup) => ( |                 {table.getHeaderGroups().map((headerGroup) => ( | ||||||
|                   <DataGridHeaderRow<TValue> key={headerGroup.id} headerGroup={headerGroup} /> |                   <DataGridHeaderRow<TValue> key={headerGroup.id} headerGroup={headerGroup} /> | ||||||
| @@ -228,7 +206,7 @@ export const DataGrid = <TValue extends object>({ | |||||||
|     </Card> |     </Card> | ||||||
|   ) : ( |   ) : ( | ||||||
|     <Box w="100%"> |     <Box w="100%"> | ||||||
|       <Flex mb={2} hidden={options.hideTableTitleRow}> |       <Flex mb={2}> | ||||||
|         <Heading size="md" my="auto" mr={2}> |         <Heading size="md" my="auto" mr={2}> | ||||||
|           {header.title} |           {header.title} | ||||||
|         </Heading> |         </Heading> | ||||||
| @@ -237,16 +215,16 @@ export const DataGrid = <TValue extends object>({ | |||||||
|         <HStack spacing={2}> |         <HStack spacing={2}> | ||||||
|           {header.otherButtons} |           {header.otherButtons} | ||||||
|           {header.addButton} |           {header.addButton} | ||||||
|           {options.hideTablePreferences ? null : ( |           { | ||||||
|             // @ts-ignore |             // @ts-ignore | ||||||
|             <TableSettingsModal<TValue> controller={controller} columns={columns} /> |             <TableSettingsModal<TValue> controller={controller} columns={columns} /> | ||||||
|           )} |           } | ||||||
|           {options.refetch ? <RefreshButton onClick={options.refetch} isCompact isFetching={isLoading} /> : null} |           {options.refetch ? <RefreshButton onClick={options.refetch} isCompact isFetching={isLoading} /> : null} | ||||||
|         </HStack> |         </HStack> | ||||||
|       </Flex> |       </Flex> | ||||||
|       <LoadingOverlay isLoading={isLoading}> |       <LoadingOverlay isLoading={isLoading}> | ||||||
|         <TableContainer minH={minimumHeight}> |         <TableContainer minH={minimumHeight}> | ||||||
|           <Table size="small" variant="simple" textColor={textColor} w="100%" fontSize="14px" key={innerTableKey}> |           <Table size="small" variant="simple" textColor={textColor} w="100%" fontSize="14px"> | ||||||
|             <Thead> |             <Thead> | ||||||
|               {table.getHeaderGroups().map((headerGroup) => ( |               {table.getHeaderGroups().map((headerGroup) => ( | ||||||
|                 <DataGridHeaderRow<TValue> key={headerGroup.id} headerGroup={headerGroup} /> |                 <DataGridHeaderRow<TValue> key={headerGroup.id} headerGroup={headerGroup} /> | ||||||
|   | |||||||
| @@ -104,43 +104,18 @@ const GlobalSearchBar = () => { | |||||||
|           .then(() => callback([])); |           .then(() => callback([])); | ||||||
|       } |       } | ||||||
|       if (v.match('^[a-fA-F0-9-*]+$')) { |       if (v.match('^[a-fA-F0-9-*]+$')) { | ||||||
|         let result: { label: string; value: string; type: 'serial' }[] = []; |  | ||||||
|         let tryAgain = true; |  | ||||||
|  |  | ||||||
|         await store |         await store | ||||||
|           .searchSerialNumber(v) |           .searchSerialNumber(v) | ||||||
|           .then((res) => { |           .then((res) => { | ||||||
|             result = res.map((r) => ({ |             callback( | ||||||
|  |               res.map((r) => ({ | ||||||
|                 label: r, |                 label: r, | ||||||
|                 value: r, |                 value: r, | ||||||
|                 type: 'serial', |                 type: 'serial', | ||||||
|             })); |               })), | ||||||
|             tryAgain = false; |             ); | ||||||
|           }) |           }) | ||||||
|           .catch(() => { |           .catch(() => []); | ||||||
|             result = []; |  | ||||||
|           }); |  | ||||||
|  |  | ||||||
|         if (tryAgain) { |  | ||||||
|           // Wait 1 second and try again |  | ||||||
|           await new Promise((resolve) => setTimeout(resolve, 1000)); |  | ||||||
|  |  | ||||||
|           await store |  | ||||||
|             .searchSerialNumber(v) |  | ||||||
|             .then((res) => { |  | ||||||
|               result = res.map((r) => ({ |  | ||||||
|                 label: r, |  | ||||||
|                 value: r, |  | ||||||
|                 type: 'serial', |  | ||||||
|               })); |  | ||||||
|               tryAgain = false; |  | ||||||
|             }) |  | ||||||
|             .catch(() => { |  | ||||||
|               result = []; |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         callback(result); |  | ||||||
|       } |       } | ||||||
|       return callback([]); |       return callback([]); | ||||||
|     }, |     }, | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ export type ConfigureModalProps = { | |||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const _ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps) => { | export const ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const toast = useToast(); |   const toast = useToast(); | ||||||
|   const configure = useConfigureDevice({ serialNumber }); |   const configure = useConfigureDevice({ serialNumber }); | ||||||
| @@ -45,7 +45,6 @@ const _ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps) => { | |||||||
|   const onImportConfiguration = () => { |   const onImportConfiguration = () => { | ||||||
|     setNewConfig(getDevice.data?.configuration ? JSON.stringify(getDevice.data.configuration, null, 4) : ''); |     setNewConfig(getDevice.data?.configuration ? JSON.stringify(getDevice.data.configuration, null, 4) : ''); | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   const isValid = React.useMemo(() => { |   const isValid = React.useMemo(() => { | ||||||
|     try { |     try { | ||||||
|       JSON.parse(newConfig); |       JSON.parse(newConfig); | ||||||
| @@ -72,19 +71,9 @@ const _ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps) => { | |||||||
|           modalProps.onClose(); |           modalProps.onClose(); | ||||||
|         }, |         }, | ||||||
|       }); |       }); | ||||||
|     } catch (e) { |     } catch (e) {} | ||||||
|       // do nothing |  | ||||||
|     } |  | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   React.useEffect(() => { |  | ||||||
|     if (modalProps.isOpen) { |  | ||||||
|       getDevice.refetch(); |  | ||||||
|     } else { |  | ||||||
|       setNewConfig(''); |  | ||||||
|     } |  | ||||||
|   }, [modalProps.isOpen]); |  | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <Modal |     <Modal | ||||||
|       {...modalProps} |       {...modalProps} | ||||||
| @@ -135,5 +124,3 @@ const _ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps) => { | |||||||
|     </Modal> |     </Modal> | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export const ConfigureModal = React.memo(_ConfigureModal); |  | ||||||
|   | |||||||
| @@ -1,5 +1,18 @@ | |||||||
| import React from 'react'; | import React from 'react'; | ||||||
| import { Box, Button, Center, Heading, IconButton, Spacer, useColorMode } from '@chakra-ui/react'; | import { | ||||||
|  |   Box, | ||||||
|  |   Button, | ||||||
|  |   Heading, | ||||||
|  |   IconButton, | ||||||
|  |   Spacer, | ||||||
|  |   Table, | ||||||
|  |   Tbody, | ||||||
|  |   Td, | ||||||
|  |   Th, | ||||||
|  |   Thead, | ||||||
|  |   Tr, | ||||||
|  |   useColorMode, | ||||||
|  | } from '@chakra-ui/react'; | ||||||
| import { JsonViewer } from '@textea/json-viewer'; | import { JsonViewer } from '@textea/json-viewer'; | ||||||
| import { ArrowLeft } from '@phosphor-icons/react'; | import { ArrowLeft } from '@phosphor-icons/react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| @@ -7,124 +20,21 @@ import { v4 as uuid } from 'uuid'; | |||||||
| import { Card } from 'components/Containers/Card'; | import { Card } from 'components/Containers/Card'; | ||||||
| import { CardBody } from 'components/Containers/Card/CardBody'; | import { CardBody } from 'components/Containers/Card/CardBody'; | ||||||
| import { CardHeader } from 'components/Containers/Card/CardHeader'; | import { CardHeader } from 'components/Containers/Card/CardHeader'; | ||||||
| import { DeviceScanResult, ScanChannel } from 'models/Device'; | import { ScanChannel } from 'models/Device'; | ||||||
| import { DataGrid } from 'components/DataTables/DataGrid'; |  | ||||||
| import { DataGridColumn, useDataGrid } from 'components/DataTables/DataGrid/useDataGrid'; |  | ||||||
|  |  | ||||||
| interface Props { | interface Props { | ||||||
|   channelInfo: ScanChannel; |   channelInfo: ScanChannel; | ||||||
| } | } | ||||||
|  | const ResultCard: React.FC<Props> = ({ channelInfo: { channel, devices } }) => { | ||||||
| const ueCell = (ies: DeviceScanResult['ies'], setIes: (ies: DeviceScanResult['ies']) => void) => ( |  | ||||||
|   <Button size="sm" colorScheme="blue" onClick={() => setIes(ies)} w="100%"> |  | ||||||
|     {ies.length} |  | ||||||
|   </Button> |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| const centerIfUndefinedCell = (v?: string | number, suffix?: string) => |  | ||||||
|   v !== undefined ? `${v}${suffix ? `${suffix}` : ''}` : <Center>-</Center>; |  | ||||||
|  |  | ||||||
| const ResultCard = ({ channelInfo: { channel, devices } }: Props) => { |  | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const { colorMode } = useColorMode(); |   const { colorMode } = useColorMode(); | ||||||
|   const [ies, setIes] = React.useState<{ content: unknown; name: string; type: number }[] | undefined>(); |   const [ies, setIes] = React.useState<{ content: unknown; name: string; type: number }[] | undefined>(); | ||||||
|   const tableController = useDataGrid({ |  | ||||||
|     tableSettingsId: 'wifiscan.devices.table', |  | ||||||
|     defaultOrder: ['ssid', 'signal', 'actions'], |  | ||||||
|     defaultSortBy: [ |  | ||||||
|       { |  | ||||||
|         desc: false, |  | ||||||
|         id: 'ssid', |  | ||||||
|       }, |  | ||||||
|     ], |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   const columns: DataGridColumn<DeviceScanResult>[] = React.useMemo( |  | ||||||
|     (): DataGridColumn<DeviceScanResult>[] => [ |  | ||||||
|       { |  | ||||||
|         id: 'ssid', |  | ||||||
|         header: 'SSID', |  | ||||||
|         footer: '', |  | ||||||
|         accessorKey: 'ssid', |  | ||||||
|         meta: { |  | ||||||
|           anchored: true, |  | ||||||
|           alwaysShow: true, |  | ||||||
|         }, |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         id: 'signal', |  | ||||||
|         header: 'Signal', |  | ||||||
|         footer: '', |  | ||||||
|         accessorKey: 'signal', |  | ||||||
|         cell: (v) => `${v.cell.row.original.signal} db`, |  | ||||||
|         meta: { |  | ||||||
|           anchored: true, |  | ||||||
|           customWidth: '80px', |  | ||||||
|           alwaysShow: true, |  | ||||||
|           rowContentOptions: { |  | ||||||
|             style: { |  | ||||||
|               textAlign: 'right', |  | ||||||
|             }, |  | ||||||
|           }, |  | ||||||
|         }, |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         id: 'station', |  | ||||||
|         header: 'UEs', |  | ||||||
|         accessorKey: 'sta_count', |  | ||||||
|         cell: (v) => centerIfUndefinedCell(v.cell.row.original.sta_count), |  | ||||||
|         meta: { |  | ||||||
|           anchored: true, |  | ||||||
|           customWidth: '40px', |  | ||||||
|           alwaysShow: true, |  | ||||||
|           rowContentOptions: { |  | ||||||
|             style: { |  | ||||||
|               textAlign: 'right', |  | ||||||
|             }, |  | ||||||
|           }, |  | ||||||
|         }, |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         id: 'utilization', |  | ||||||
|         header: 'Ch. Util.', |  | ||||||
|         accessorKey: 'ch_util', |  | ||||||
|         cell: (v) => centerIfUndefinedCell(v.cell.row.original.ch_util, '%'), |  | ||||||
|         meta: { |  | ||||||
|           anchored: true, |  | ||||||
|           customWidth: '60px', |  | ||||||
|           alwaysShow: true, |  | ||||||
|           headerOptions: { |  | ||||||
|             tooltip: 'Channel Utilization (%)', |  | ||||||
|           }, |  | ||||||
|           rowContentOptions: { |  | ||||||
|             style: { |  | ||||||
|               textAlign: 'right', |  | ||||||
|             }, |  | ||||||
|           }, |  | ||||||
|         }, |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         id: 'ies', |  | ||||||
|         header: 'Ies', |  | ||||||
|         footer: '', |  | ||||||
|         accessorKey: 'actions', |  | ||||||
|         cell: (v) => ueCell(v.cell.row.original.ies ?? [], setIes), |  | ||||||
|         meta: { |  | ||||||
|           customWidth: '50px', |  | ||||||
|           isCentered: true, |  | ||||||
|           alwaysShow: true, |  | ||||||
|         }, |  | ||||||
|       }, |  | ||||||
|     ], |  | ||||||
|     [t], |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <Card> |     <Card variant="widget"> | ||||||
|       <CardHeader display="flex"> |       <CardHeader display="flex"> | ||||||
|         <Heading size="md" my="auto"> |         <Heading size="md" my="auto"> | ||||||
|           {t('commands.channel')} #{channel} ({devices.length}{' '} |           {t('commands.channel')} #{channel} ({devices.length} {t('devices.title')}) | ||||||
|           {devices.length === 1 ? t('devices.one') : t('devices.title')}) |  | ||||||
|         </Heading> |         </Heading> | ||||||
|         <Spacer /> |         <Spacer /> | ||||||
|         {ies && ( |         {ies && ( | ||||||
| @@ -139,6 +49,7 @@ const ResultCard = ({ channelInfo: { channel, devices } }: Props) => { | |||||||
|         )} |         )} | ||||||
|       </CardHeader> |       </CardHeader> | ||||||
|       <CardBody> |       <CardBody> | ||||||
|  |         <Box h="400px" w="100%" overflowY="auto" overflowX="auto" px={0}> | ||||||
|           {ies ? ( |           {ies ? ( | ||||||
|             <Box w="800px"> |             <Box w="800px"> | ||||||
|               {ies.map(({ content, name, type }) => ( |               {ies.map(({ content, name, type }) => ( | ||||||
| @@ -158,24 +69,32 @@ const ResultCard = ({ channelInfo: { channel, devices } }: Props) => { | |||||||
|               ))} |               ))} | ||||||
|             </Box> |             </Box> | ||||||
|           ) : ( |           ) : ( | ||||||
|           <DataGrid<DeviceScanResult> |             <Table variant="simple" px={0}> | ||||||
|             controller={tableController} |               <Thead> | ||||||
|             header={{ |                 <Tr> | ||||||
|               title: '', |                   <Th>SSID</Th> | ||||||
|               objectListed: t('devices.title'), |                   <Th width="110px" isNumeric> | ||||||
|             }} |                     {t('commands.signal')} | ||||||
|             columns={columns} |                   </Th> | ||||||
|             data={devices} |                   <Th w="10px">IEs</Th> | ||||||
|             options={{ |                 </Tr> | ||||||
|               count: devices.length, |               </Thead> | ||||||
|               onRowClick: (device) => () => setIes(device.ies ?? []), |               <Tbody> | ||||||
|               hideTablePreferences: true, |                 {devices.map((dev) => ( | ||||||
|               isHidingControls: true, |                   <Tr key={uuid()}> | ||||||
|               minimumHeight: '0px', |                     <Td>{dev.ssid}</Td> | ||||||
|               hideTableTitleRow: true, |                     <Td width="110px">{dev.signal} db</Td> | ||||||
|             }} |                     <Td w="10px"> | ||||||
|           /> |                       <Button size="sm" colorScheme="blue" onClick={() => setIes(dev.ies ?? [])}> | ||||||
|  |                         {dev.ies?.length ?? 0} | ||||||
|  |                       </Button> | ||||||
|  |                     </Td> | ||||||
|  |                   </Tr> | ||||||
|  |                 ))} | ||||||
|  |               </Tbody> | ||||||
|  |             </Table> | ||||||
|           )} |           )} | ||||||
|  |         </Box> | ||||||
|       </CardBody> |       </CardBody> | ||||||
|     </Card> |     </Card> | ||||||
|   ); |   ); | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import React, { useEffect, useMemo } from 'react'; | import React, { useEffect, useMemo } from 'react'; | ||||||
| import { Alert, Heading, VStack } from '@chakra-ui/react'; | import { Alert, Heading, SimpleGrid } from '@chakra-ui/react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { v4 as uuid } from 'uuid'; | import { v4 as uuid } from 'uuid'; | ||||||
| import ResultCard from './ResultCard'; | import ResultCard from './ResultCard'; | ||||||
| @@ -11,7 +11,7 @@ interface Props { | |||||||
|   setCsvData: (data: DeviceScanResult[]) => void; |   setCsvData: (data: DeviceScanResult[]) => void; | ||||||
| } | } | ||||||
|  |  | ||||||
| const WifiScanResultDisplay = ({ results, setCsvData }: Props) => { | const WifiScanResultDisplay: React.FC<Props> = ({ results, setCsvData }) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|  |  | ||||||
|   const scanResults = useMemo(() => { |   const scanResults = useMemo(() => { | ||||||
| @@ -54,18 +54,18 @@ const WifiScanResultDisplay = ({ results, setCsvData }: Props) => { | |||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       {results.errorCode === 1 && ( |       {results.errorCode === 1 && ( | ||||||
|         <Heading size="md"> |         <Heading size="sm"> | ||||||
|           <Alert colorScheme="red">{t('commands.wifiscan_error_1')}</Alert> |           <Alert colorScheme="red">{t('commands.wifiscan_error_1')}</Alert> | ||||||
|         </Heading> |         </Heading> | ||||||
|       )} |       )} | ||||||
|       <Heading size="md" mb={2}> |       <Heading size="sm"> | ||||||
|         {t('commands.execution_time')}: {Math.floor(results.executionTime / 1000)}s |         {t('commands.execution_time')}: {Math.floor(results.executionTime / 1000)}s | ||||||
|       </Heading> |       </Heading> | ||||||
|       <VStack spacing={4} align="stretch"> |       <SimpleGrid minChildWidth="360px" spacing={2}> | ||||||
|         {scanResults?.scanList.map((channel) => ( |         {scanResults?.scanList.map((channel) => ( | ||||||
|           <ResultCard key={uuid()} channelInfo={channel} /> |           <ResultCard key={uuid()} channelInfo={channel} /> | ||||||
|         ))} |         ))} | ||||||
|       </VStack> |       </SimpleGrid> | ||||||
|     </> |     </> | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -187,8 +187,6 @@ export const useConfigureDevice = ({ serialNumber }: { serialNumber: string }) = | |||||||
|   return useMutation(configureDevice(serialNumber), { |   return useMutation(configureDevice(serialNumber), { | ||||||
|     onSuccess: () => { |     onSuccess: () => { | ||||||
|       queryClient.invalidateQueries(['commands', serialNumber]); |       queryClient.invalidateQueries(['commands', serialNumber]); | ||||||
|       queryClient.invalidateQueries(['device', serialNumber]); |  | ||||||
|       queryClient.invalidateQueries(['devices']); |  | ||||||
|     }, |     }, | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| @@ -250,14 +248,27 @@ const startScript = (data: { serialNumber: string; timeout?: number; [k: string] | |||||||
|     }) |     }) | ||||||
|     .then((response: { data: DeviceCommandHistory }) => response.data); |     .then((response: { data: DeviceCommandHistory }) => response.data); | ||||||
| export const useDeviceScript = ({ serialNumber }: { serialNumber: string }) => { | export const useDeviceScript = ({ serialNumber }: { serialNumber: string }) => { | ||||||
|  |   const { t } = useTranslation(); | ||||||
|  |   const toast = useToast(); | ||||||
|   const queryClient = useQueryClient(); |   const queryClient = useQueryClient(); | ||||||
|  |  | ||||||
|   return useMutation(startScript, { |   return useMutation(startScript, { | ||||||
|     onSuccess: () => { |     onSuccess: () => { | ||||||
|       queryClient.invalidateQueries(['commands', serialNumber]); |       queryClient.invalidateQueries(['commands', serialNumber]); | ||||||
|     }, |     }, | ||||||
|     onError: () => { |     onError: (e) => { | ||||||
|       queryClient.invalidateQueries(['commands', serialNumber]); |       queryClient.invalidateQueries(['commands', serialNumber]); | ||||||
|  |       if (axios.isAxiosError(e)) { | ||||||
|  |         toast({ | ||||||
|  |           id: 'script-error', | ||||||
|  |           title: t('common.error'), | ||||||
|  |           description: e?.response?.data?.ErrorDescription, | ||||||
|  |           status: 'error', | ||||||
|  |           duration: 5000, | ||||||
|  |           isClosable: true, | ||||||
|  |           position: 'top-right', | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|     }, |     }, | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,173 +0,0 @@ | |||||||
| import { QueryFunctionContext, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; |  | ||||||
| import { axiosGw, axiosOwls } from 'constants/axiosInstances'; |  | ||||||
| import { AtLeast } from 'models/General'; |  | ||||||
|  |  | ||||||
| export type Simulation = { |  | ||||||
|   clientInterval: number; |  | ||||||
|   concurrentDeviceS: number; |  | ||||||
|   deviceType: string; |  | ||||||
|   devices: number; |  | ||||||
|   gateway: string; |  | ||||||
|   healthCheckInterval: number; |  | ||||||
|   id: string; |  | ||||||
|   keepAlive: number; |  | ||||||
|   key: string; |  | ||||||
|   macPrefix: string; |  | ||||||
|   minAssociations: number; |  | ||||||
|   maxAssociations: number; |  | ||||||
|   minClients: number; |  | ||||||
|   maxClients: number; |  | ||||||
|   name: string; |  | ||||||
|   reconnectionInterval: number; |  | ||||||
|   simulationLength: number; |  | ||||||
|   stateInterval: number; |  | ||||||
|   threads: number; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const getSimulations = () => async () => |  | ||||||
|   axiosOwls.get(`simulation/*`).then((response) => response.data as { list: Simulation[] }); |  | ||||||
|  |  | ||||||
| export const useGetSimulations = () => |  | ||||||
|   useQuery(['simulations'], getSimulations(), { |  | ||||||
|     keepPreviousData: true, |  | ||||||
|     staleTime: 30000, |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
| const getSimulation = (id?: string) => async () => |  | ||||||
|   axiosOwls.get(`simulation/${id}`).then((response) => response.data as { list: Simulation[] }); |  | ||||||
| export const useGetSimulation = ({ id }: { id?: string }) => |  | ||||||
|   useQuery(['simulation', id], getSimulation(id), { |  | ||||||
|     keepPreviousData: true, |  | ||||||
|     enabled: id !== undefined, |  | ||||||
|     staleTime: 30000, |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
| const createSimulation = async (newSimulation: Partial<Simulation>) => axiosOwls.post(`simulation/0`, newSimulation); |  | ||||||
| export const useCreateSimulation = () => { |  | ||||||
|   const queryClient = useQueryClient(); |  | ||||||
|  |  | ||||||
|   return useMutation(createSimulation, { |  | ||||||
|     onSuccess: () => { |  | ||||||
|       queryClient.invalidateQueries(['simulations']); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const updateSimulation = async (newSimulation: AtLeast<Simulation, 'id'>) => |  | ||||||
|   axiosOwls.put(`simulation/${newSimulation.id}`, newSimulation).then((response) => response.data as Simulation); |  | ||||||
| export const useUpdateSimulation = () => { |  | ||||||
|   const queryClient = useQueryClient(); |  | ||||||
|  |  | ||||||
|   return useMutation(updateSimulation, { |  | ||||||
|     onSuccess: (newSimulation) => { |  | ||||||
|       queryClient.setQueryData(['simulation'], newSimulation); |  | ||||||
|       queryClient.invalidateQueries(['simulations']); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const deleteSimulation = async ({ id }: { id: string }) => axiosOwls.delete(`simulation/${id}`); |  | ||||||
| export const useDeleteSimulation = () => { |  | ||||||
|   const queryClient = useQueryClient(); |  | ||||||
|  |  | ||||||
|   return useMutation(deleteSimulation, { |  | ||||||
|     onSuccess: () => { |  | ||||||
|       queryClient.invalidateQueries(['simulations']); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const startSimulation = async ({ id }: { id: string }) => axiosOwls.post(`operation/${id}?operation=start`); |  | ||||||
| export const useStartSimulation = () => { |  | ||||||
|   const queryClient = useQueryClient(); |  | ||||||
|  |  | ||||||
|   return useMutation(startSimulation, { |  | ||||||
|     onSuccess: () => { |  | ||||||
|       queryClient.invalidateQueries(['simulations', 'status']); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
| const stopSimulation = async ({ runId, simulationId }: { simulationId: string; runId: string }) => |  | ||||||
|   axiosOwls.post(`operation/${simulationId}?runningId=${runId}&operation=stop`); |  | ||||||
| export const useStopSimulation = () => { |  | ||||||
|   const queryClient = useQueryClient(); |  | ||||||
|  |  | ||||||
|   return useMutation(stopSimulation, { |  | ||||||
|     onSuccess: () => { |  | ||||||
|       queryClient.invalidateQueries(['simulations', 'status']); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
| const cancelSimulation = async ({ runId, simulationId }: { simulationId: string; runId: string }) => |  | ||||||
|   axiosOwls.post(`operation/${simulationId}?runningId=${runId}&operation=cancel`); |  | ||||||
| export const useCancelSimulation = () => { |  | ||||||
|   const queryClient = useQueryClient(); |  | ||||||
|  |  | ||||||
|   return useMutation(cancelSimulation, { |  | ||||||
|     onSuccess: () => { |  | ||||||
|       queryClient.invalidateQueries(['simulations', 'status']); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export type SimulationStatus = { |  | ||||||
|   endTime: number; |  | ||||||
|   errorDevices: number; |  | ||||||
|   id: string; |  | ||||||
|   liveDevices: number; |  | ||||||
|   msgsRx: number; |  | ||||||
|   msgsTx: number; |  | ||||||
|   owner: string; |  | ||||||
|   rx: number; |  | ||||||
|   simulationId: string; |  | ||||||
|   startTime: number; |  | ||||||
|   state: 'running' | 'completed' | 'cancelled' | 'none'; |  | ||||||
|   timeToFullDevices: number; |  | ||||||
|   tx: number; |  | ||||||
| }; |  | ||||||
| const getSimulationsStatus = async () => |  | ||||||
|   axiosOwls.get(`status/*`).then((response) => response.data as SimulationStatus[]); |  | ||||||
| export const useGetSimulationsStatus = () => |  | ||||||
|   useQuery(['simulations', 'status'], getSimulationsStatus, { |  | ||||||
|     keepPreviousData: true, |  | ||||||
|     staleTime: Infinity, |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
| const getSimulationStatus = async (context: QueryFunctionContext<[string, string, string]>) => |  | ||||||
|   axiosOwls.get(`status/${context.queryKey[2]}`).then((response) => response.data as SimulationStatus); |  | ||||||
| export const useGetSimulationStatus = ({ id }: { id: string }) => |  | ||||||
|   useQuery(['simulations', 'status', id], getSimulationStatus, { |  | ||||||
|     keepPreviousData: true, |  | ||||||
|     staleTime: Infinity, |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
| const getSimulationHistory = async (context: QueryFunctionContext<[string, string, string]>) => |  | ||||||
|   axiosOwls.get(`results/${context.queryKey[2]}`).then((response) => response.data.list as SimulationStatus[]); |  | ||||||
| export const useGetSimulationHistory = ({ id }: { id: string }) => |  | ||||||
|   useQuery(['simulations', 'history', id], getSimulationHistory, { |  | ||||||
|     keepPreviousData: true, |  | ||||||
|     enabled: !!id, |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
| const deleteSimulationResult = async ({ id }: { id: string }) => axiosOwls.delete(`results/${id}`); |  | ||||||
| export const useDeleteSimulationResult = () => { |  | ||||||
|   const queryClient = useQueryClient(); |  | ||||||
|  |  | ||||||
|   return useMutation(deleteSimulationResult, { |  | ||||||
|     onSuccess: () => { |  | ||||||
|       queryClient.invalidateQueries(['simulations', 'history']); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const deleteSimulatedDevices = async () => axiosGw.delete('devices?simulatedDevices=true'); |  | ||||||
|  |  | ||||||
| export const useDeleteSimulatedDevices = () => { |  | ||||||
|   const queryClient = useQueryClient(); |  | ||||||
|  |  | ||||||
|   return useMutation(deleteSimulatedDevices, { |  | ||||||
|     onSuccess: () => { |  | ||||||
|       queryClient.invalidateQueries(['devices']); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
| @@ -1,80 +0,0 @@ | |||||||
| import * as React from 'react'; |  | ||||||
| import { useToast } from '@chakra-ui/react'; |  | ||||||
| import { useTranslation } from 'react-i18next'; |  | ||||||
| import { v4 as uuid } from 'uuid'; |  | ||||||
| import { isApiError } from 'models/Axios'; |  | ||||||
|  |  | ||||||
| export type SuccessNotificationProps = { |  | ||||||
|   description: string; |  | ||||||
|   id?: string; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export type ApiErrorNotificationProps = { |  | ||||||
|   e: unknown; |  | ||||||
|   fallbackMessage?: string; |  | ||||||
|   id?: string; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const useNotification = () => { |  | ||||||
|   const { t } = useTranslation(); |  | ||||||
|   const toast = useToast(); |  | ||||||
|  |  | ||||||
|   const successToast = ({ description, id }: SuccessNotificationProps) => { |  | ||||||
|     toast({ |  | ||||||
|       id: id ?? uuid(), |  | ||||||
|       title: t('common.success'), |  | ||||||
|       description, |  | ||||||
|       status: 'success', |  | ||||||
|       duration: 3000, |  | ||||||
|       isClosable: true, |  | ||||||
|       position: 'top-right', |  | ||||||
|     }); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   const apiErrorToast = ({ e, id, fallbackMessage }: ApiErrorNotificationProps) => { |  | ||||||
|     if (isApiError(e)) { |  | ||||||
|       toast({ |  | ||||||
|         id: id ?? uuid(), |  | ||||||
|         title: t('common.error'), |  | ||||||
|         description: e.response?.data.ErrorDescription, |  | ||||||
|         status: 'error', |  | ||||||
|         duration: 5000, |  | ||||||
|         isClosable: true, |  | ||||||
|         position: 'top-right', |  | ||||||
|       }); |  | ||||||
|     } else { |  | ||||||
|       toast({ |  | ||||||
|         id: id ?? uuid(), |  | ||||||
|         title: t('common.error'), |  | ||||||
|         description: fallbackMessage, |  | ||||||
|         status: 'error', |  | ||||||
|         duration: 5000, |  | ||||||
|         isClosable: true, |  | ||||||
|         position: 'top-right', |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   const errorToast = ({ description, id }: SuccessNotificationProps) => { |  | ||||||
|     toast({ |  | ||||||
|       id: id ?? uuid(), |  | ||||||
|       title: t('common.error'), |  | ||||||
|       description, |  | ||||||
|       status: 'error', |  | ||||||
|       duration: 5000, |  | ||||||
|       isClosable: true, |  | ||||||
|       position: 'top-right', |  | ||||||
|     }); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   return React.useMemo( |  | ||||||
|     () => ({ |  | ||||||
|       successToast, |  | ||||||
|       errorToast, |  | ||||||
|       apiErrorToast, |  | ||||||
|     }), |  | ||||||
|     [t], |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export type UseNotificationReturn = ReturnType<typeof useNotification>; |  | ||||||
| @@ -123,7 +123,6 @@ export const Navbar = ({ | |||||||
|         top="15px" |         top="15px" | ||||||
|         border={scrolled ? '0.5px solid' : undefined} |         border={scrolled ? '0.5px solid' : undefined} | ||||||
|         w={isCompact ? '100%' : 'calc(100% - 254px)'} |         w={isCompact ? '100%' : 'calc(100% - 254px)'} | ||||||
|         zIndex={10} |  | ||||||
|       > |       > | ||||||
|         <Flex |         <Flex | ||||||
|           w="100%" |           w="100%" | ||||||
|   | |||||||
| @@ -1,6 +1,3 @@ | |||||||
| import { AxiosError as Err, isAxiosError } from 'axios'; | import { AxiosError as Err } from 'axios'; | ||||||
|  |  | ||||||
| export type AxiosError = Err<{ ErrorDescription: string; ErrorCode: number }>; | export type AxiosError = Err<{ ErrorDescription: string; ErrorCode: number }>; | ||||||
|  |  | ||||||
| export const isApiError = (e: unknown): e is AxiosError => |  | ||||||
|   isAxiosError(e) && (e as AxiosError).response?.data?.ErrorDescription !== undefined; |  | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ import { Note } from './Note'; | |||||||
|  |  | ||||||
| export interface GatewayDevice { | export interface GatewayDevice { | ||||||
|   UUID: number; |   UUID: number; | ||||||
|   certificateExpiryDate: number; |  | ||||||
|   compatible: string; |   compatible: string; | ||||||
|   configuration: unknown; |   configuration: unknown; | ||||||
|   createdTimestamp: number; |   createdTimestamp: number; | ||||||
| @@ -17,7 +16,6 @@ export interface GatewayDevice { | |||||||
|   lastConfigurationChange: number; |   lastConfigurationChange: number; | ||||||
|   lastConfigurationDownload: number; |   lastConfigurationDownload: number; | ||||||
|   lastFWUpdate: number; |   lastFWUpdate: number; | ||||||
|   lastRecordedContact: number; |  | ||||||
|   locale: string; |   locale: string; | ||||||
|   location: string; |   location: string; | ||||||
|   macAddress: string; |   macAddress: string; | ||||||
| @@ -114,16 +112,12 @@ interface BssidResult { | |||||||
|   bssid: string; |   bssid: string; | ||||||
|   capability: number; |   capability: number; | ||||||
|   channel: number; |   channel: number; | ||||||
|   /** Channel Utilization percentage (ex.: 28 -> 28% channel utilization) */ |  | ||||||
|   ch_util?: number; |  | ||||||
|   frequency: number; |   frequency: number; | ||||||
|   ht_oper: string; |   ht_oper: string; | ||||||
|   ies: { content: unknown; name: string; type: number }[]; |   ies: { content: unknown; name: string; type: number }[]; | ||||||
|   last_seen: number; |   last_seen: number; | ||||||
|   ssid: string; |   ssid: string; | ||||||
|   signal: number; |   signal: number; | ||||||
|   /** Station count */ |  | ||||||
|   sta_count?: number; |  | ||||||
|   tsf: number; |   tsf: number; | ||||||
|   meshid?: string; |   meshid?: string; | ||||||
|   vht_oper: string; |   vht_oper: string; | ||||||
| @@ -148,8 +142,20 @@ export interface WifiScanResult { | |||||||
|   }; |   }; | ||||||
| } | } | ||||||
|  |  | ||||||
| export type DeviceScanResult = BssidResult; | export interface DeviceScanResult { | ||||||
|  |   bssid: string; | ||||||
|  |   capability: number; | ||||||
|  |   channel: number; | ||||||
|  |   frequency: number; | ||||||
|  |   ht_oper: string; | ||||||
|  |   ies: { content: unknown; name: string; type: number }[]; | ||||||
|  |   last_seen: number; | ||||||
|  |   ssid: string; | ||||||
|  |   signal: number | string; | ||||||
|  |   tsf: number; | ||||||
|  |   meshid?: string; | ||||||
|  |   vht_oper: string; | ||||||
|  | } | ||||||
| export interface ScanChannel { | export interface ScanChannel { | ||||||
|   channel: number; |   channel: number; | ||||||
|   devices: DeviceScanResult[]; |   devices: DeviceScanResult[]; | ||||||
|   | |||||||
| @@ -1,93 +0,0 @@ | |||||||
| import * as React from 'react'; |  | ||||||
| import { |  | ||||||
|   Box, |  | ||||||
|   Button, |  | ||||||
|   Center, |  | ||||||
|   Heading, |  | ||||||
|   Popover, |  | ||||||
|   PopoverArrow, |  | ||||||
|   PopoverBody, |  | ||||||
|   PopoverCloseButton, |  | ||||||
|   PopoverContent, |  | ||||||
|   PopoverHeader, |  | ||||||
|   PopoverTrigger, |  | ||||||
|   Text, |  | ||||||
| } from '@chakra-ui/react'; |  | ||||||
| import { Trash } from '@phosphor-icons/react'; |  | ||||||
| import { Card } from 'components/Containers/Card'; |  | ||||||
| import { CardHeader } from 'components/Containers/Card/CardHeader'; |  | ||||||
| import { CardBody } from 'components/Containers/Card/CardBody'; |  | ||||||
| import { DeleteButton } from 'components/Buttons/DeleteButton'; |  | ||||||
| import { useNotification } from 'hooks/useNotification'; |  | ||||||
| import { useDeleteSimulatedDevices } from 'hooks/Network/Simulations'; |  | ||||||
|  |  | ||||||
| const AdvancedSystemPage = () => { |  | ||||||
|   const { successToast, apiErrorToast } = useNotification(); |  | ||||||
|   const deleteSimulatedDevices = useDeleteSimulatedDevices(); |  | ||||||
|  |  | ||||||
|   const handleDeleteSimulatedDevices = async () => |  | ||||||
|     deleteSimulatedDevices.mutateAsync(undefined, { |  | ||||||
|       onSuccess: () => { |  | ||||||
|         successToast({ |  | ||||||
|           id: 'delete-simulated-devices', |  | ||||||
|           description: 'Simulated devices deleted!', |  | ||||||
|         }); |  | ||||||
|       }, |  | ||||||
|       onError: (e) => { |  | ||||||
|         apiErrorToast({ |  | ||||||
|           id: 'delete-simulated-devices', |  | ||||||
|           e, |  | ||||||
|           fallbackMessage: 'Error deleting simulated devices', |  | ||||||
|         }); |  | ||||||
|       }, |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <Card> |  | ||||||
|       <CardHeader> |  | ||||||
|         <Heading size="md">Operations</Heading> |  | ||||||
|       </CardHeader> |  | ||||||
|       <CardBody> |  | ||||||
|         <Box> |  | ||||||
|           <Heading size="sm">Delete Simulated Devices</Heading> |  | ||||||
|           <Text fontStyle="italic">Delete all simulated devices from the database. This action cannot be undone.</Text> |  | ||||||
|           <Popover> |  | ||||||
|             {({ onClose }) => ( |  | ||||||
|               <> |  | ||||||
|                 <PopoverTrigger> |  | ||||||
|                   <Button colorScheme="red" rightIcon={<Trash size={20} />}> |  | ||||||
|                     Delete |  | ||||||
|                   </Button> |  | ||||||
|                 </PopoverTrigger> |  | ||||||
|                 <PopoverContent> |  | ||||||
|                   <PopoverArrow /> |  | ||||||
|                   <PopoverCloseButton /> |  | ||||||
|                   <PopoverHeader>Confirm</PopoverHeader> |  | ||||||
|                   <PopoverBody> |  | ||||||
|                     <Text>Are you sure you want to delete all simulated devices?</Text> |  | ||||||
|                     <Center mt={4}> |  | ||||||
|                       <Button onClick={onClose} mr={1}> |  | ||||||
|                         Cancel |  | ||||||
|                       </Button> |  | ||||||
|                       <DeleteButton |  | ||||||
|                         ml={1} |  | ||||||
|                         isLoading={deleteSimulatedDevices.isLoading} |  | ||||||
|                         onClick={async () => { |  | ||||||
|                           await handleDeleteSimulatedDevices(); |  | ||||||
|                           onClose(); |  | ||||||
|                         }} |  | ||||||
|                         isCompact={false} |  | ||||||
|                       /> |  | ||||||
|                     </Center> |  | ||||||
|                   </PopoverBody> |  | ||||||
|                 </PopoverContent> |  | ||||||
|               </> |  | ||||||
|             )} |  | ||||||
|           </Popover> |  | ||||||
|         </Box> |  | ||||||
|       </CardBody> |  | ||||||
|     </Card> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export default AdvancedSystemPage; |  | ||||||
| @@ -11,6 +11,7 @@ import { compactDate } from 'helpers/dateFormatting'; | |||||||
| import { useGetDevice } from 'hooks/Network/Devices'; | import { useGetDevice } from 'hooks/Network/Devices'; | ||||||
| import { useGetProvUi } from 'hooks/Network/Endpoints'; | import { useGetProvUi } from 'hooks/Network/Endpoints'; | ||||||
| import { useGetTag } from 'hooks/Network/Inventory'; | import { useGetTag } from 'hooks/Network/Inventory'; | ||||||
|  | import { DeviceConfiguration } from 'models/Device'; | ||||||
|  |  | ||||||
| type Props = { | type Props = { | ||||||
|   serialNumber: string; |   serialNumber: string; | ||||||
| @@ -59,7 +60,7 @@ const DeviceDetails = ({ serialNumber }: Props) => { | |||||||
|         <Heading size="md">{t('common.details')}</Heading> |         <Heading size="md">{t('common.details')}</Heading> | ||||||
|         <Spacer /> |         <Spacer /> | ||||||
|         <ViewCapabilitiesModal serialNumber={serialNumber} /> |         <ViewCapabilitiesModal serialNumber={serialNumber} /> | ||||||
|         <ViewConfigurationModal serialNumber={serialNumber} /> |         <ViewConfigurationModal configuration={getDevice.data?.configuration as DeviceConfiguration} /> | ||||||
|       </CardHeader> |       </CardHeader> | ||||||
|       <CardBody display="block"> |       <CardBody display="block"> | ||||||
|         <Grid templateColumns="repeat(2, 1fr)" gap={0} w="100%"> |         <Grid templateColumns="repeat(2, 1fr)" gap={0} w="100%"> | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ import { CardHeader } from 'components/Containers/Card/CardHeader'; | |||||||
| import FormattedDate from 'components/InformationDisplays/FormattedDate'; | import FormattedDate from 'components/InformationDisplays/FormattedDate'; | ||||||
| import COUNTRY_LIST from 'constants/countryList'; | import COUNTRY_LIST from 'constants/countryList'; | ||||||
| import { compactDate, compactSecondsToDetailed } from 'helpers/dateFormatting'; | import { compactDate, compactSecondsToDetailed } from 'helpers/dateFormatting'; | ||||||
| import { bytesString, getRevision, uppercaseFirstLetter } from 'helpers/stringHelper'; | import { bytesString, getRevision } from 'helpers/stringHelper'; | ||||||
| import { useGetDevice, useGetDeviceStatus } from 'hooks/Network/Devices'; | import { useGetDevice, useGetDeviceStatus } from 'hooks/Network/Devices'; | ||||||
| import { useGetDeviceLastStats } from 'hooks/Network/Statistics'; | import { useGetDeviceLastStats } from 'hooks/Network/Statistics'; | ||||||
|  |  | ||||||
| @@ -157,11 +157,7 @@ const DeviceSummary = ({ serialNumber }: Props) => { | |||||||
|               <Heading size="sm">{t('analytics.last_contact')}:</Heading> |               <Heading size="sm">{t('analytics.last_contact')}:</Heading> | ||||||
|             </GridItem> |             </GridItem> | ||||||
|             <GridItem colSpan={1}> |             <GridItem colSpan={1}> | ||||||
|               {getStatus?.data?.lastContact && getStatus?.data.lastContact !== 0 ? ( |               {getStatus?.data?.lastContact ? <FormattedDate date={getStatus.data.lastContact} /> : ''} | ||||||
|                 <FormattedDate date={getStatus.data.lastContact} /> |  | ||||||
|               ) : ( |  | ||||||
|                 <FormattedDate date={getDevice.data?.lastRecordedContact} /> |  | ||||||
|               )} |  | ||||||
|             </GridItem> |             </GridItem> | ||||||
|             <GridItem colSpan={1} alignContent="center" alignItems="center"> |             <GridItem colSpan={1} alignContent="center" alignItems="center"> | ||||||
|               <Heading size="sm">{t('analytics.memory')}:</Heading> |               <Heading size="sm">{t('analytics.memory')}:</Heading> | ||||||
| @@ -171,10 +167,8 @@ const DeviceSummary = ({ serialNumber }: Props) => { | |||||||
|               <Heading size="sm">{t('devices.certificate_expires_in')}:</Heading> |               <Heading size="sm">{t('devices.certificate_expires_in')}:</Heading> | ||||||
|             </GridItem> |             </GridItem> | ||||||
|             <GridItem colSpan={1}> |             <GridItem colSpan={1}> | ||||||
|               {getDevice.data?.certificateExpiryDate ? ( |               {getStatus.data?.certificateExpiryDate && ( | ||||||
|                 <FormattedDate date={getDevice.data?.certificateExpiryDate} hidePrefix /> |                 <FormattedDate date={getStatus.data?.certificateExpiryDate} hidePrefix /> | ||||||
|               ) : ( |  | ||||||
|                 '-' |  | ||||||
|               )} |               )} | ||||||
|             </GridItem> |             </GridItem> | ||||||
|             <GridItem colSpan={1} alignContent="center" alignItems="center"> |             <GridItem colSpan={1} alignContent="center" alignItems="center"> | ||||||
| @@ -182,7 +176,7 @@ const DeviceSummary = ({ serialNumber }: Props) => { | |||||||
|             </GridItem> |             </GridItem> | ||||||
|             <GridItem colSpan={1}> |             <GridItem colSpan={1}> | ||||||
|               {getStatus.data?.connectReason && getStatus.data?.connectReason.length > 0 |               {getStatus.data?.connectReason && getStatus.data?.connectReason.length > 0 | ||||||
|                 ? uppercaseFirstLetter(getStatus.data.connectReason) |                 ? getStatus.data?.connectReason | ||||||
|                 : '-'} |                 : '-'} | ||||||
|             </GridItem> |             </GridItem> | ||||||
|           </Grid> |           </Grid> | ||||||
|   | |||||||
| @@ -7,9 +7,7 @@ import { | |||||||
|   AccordionPanel, |   AccordionPanel, | ||||||
|   Box, |   Box, | ||||||
|   Button, |   Button, | ||||||
|   Center, |  | ||||||
|   IconButton, |   IconButton, | ||||||
|   Spinner, |  | ||||||
|   Tooltip, |   Tooltip, | ||||||
|   useClipboard, |   useClipboard, | ||||||
|   useColorMode, |   useColorMode, | ||||||
| @@ -19,26 +17,19 @@ import { JsonViewer } from '@textea/json-viewer'; | |||||||
| import { Barcode } from '@phosphor-icons/react'; | import { Barcode } from '@phosphor-icons/react'; | ||||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||||
| import { Modal } from 'components/Modals/Modal'; | import { Modal } from 'components/Modals/Modal'; | ||||||
| import { useGetDevice } from 'hooks/Network/Devices'; | import { DeviceConfiguration } from 'models/Device'; | ||||||
| import { RefreshButton } from 'components/Buttons/RefreshButton'; |  | ||||||
|  |  | ||||||
| const ViewConfigurationModal = ({ serialNumber }: { serialNumber: string }) => { | const ViewConfigurationModal = ({ configuration }: { configuration?: DeviceConfiguration }) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const getDevice = useGetDevice({ serialNumber }); |  | ||||||
|   const { isOpen, onOpen, onClose } = useDisclosure(); |   const { isOpen, onOpen, onClose } = useDisclosure(); | ||||||
|   const { hasCopied, onCopy, setValue } = useClipboard(JSON.stringify(getDevice.data?.configuration ?? {}, null, 2)); |   const { hasCopied, onCopy, setValue } = useClipboard(JSON.stringify(configuration ?? {}, null, 2)); | ||||||
|   const { colorMode } = useColorMode(); |   const { colorMode } = useColorMode(); | ||||||
|  |  | ||||||
|   React.useEffect(() => { |   React.useEffect(() => { | ||||||
|     if (getDevice.data) { |     if (configuration) { | ||||||
|       setValue(JSON.stringify(getDevice.data.configuration, null, 2)); |       setValue(JSON.stringify(configuration, null, 2)); | ||||||
|     } |     } | ||||||
|   }, [getDevice.data?.configuration]); |   }, [configuration]); | ||||||
|  |  | ||||||
|   const handleOpenClick = () => { |  | ||||||
|     getDevice.refetch(); |  | ||||||
|     onOpen(); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
| @@ -46,7 +37,7 @@ const ViewConfigurationModal = ({ serialNumber }: { serialNumber: string }) => { | |||||||
|         <IconButton |         <IconButton | ||||||
|           aria-label={t('configurations.one')} |           aria-label={t('configurations.one')} | ||||||
|           icon={<Barcode size={20} />} |           icon={<Barcode size={20} />} | ||||||
|           onClick={handleOpenClick} |           onClick={onOpen} | ||||||
|           colorScheme="purple" |           colorScheme="purple" | ||||||
|         /> |         /> | ||||||
|       </Tooltip> |       </Tooltip> | ||||||
| @@ -54,17 +45,14 @@ const ViewConfigurationModal = ({ serialNumber }: { serialNumber: string }) => { | |||||||
|         isOpen={isOpen} |         isOpen={isOpen} | ||||||
|         title={t('configurations.one')} |         title={t('configurations.one')} | ||||||
|         topRightButtons={ |         topRightButtons={ | ||||||
|           <> |  | ||||||
|           <Button onClick={onCopy} size="md" colorScheme="teal"> |           <Button onClick={onCopy} size="md" colorScheme="teal"> | ||||||
|             {hasCopied ? `${t('common.copied')}!` : t('common.copy')} |             {hasCopied ? `${t('common.copied')}!` : t('common.copy')} | ||||||
|           </Button> |           </Button> | ||||||
|             <RefreshButton onClick={getDevice.refetch} isFetching={getDevice.isFetching} /> |  | ||||||
|           </> |  | ||||||
|         } |         } | ||||||
|         onClose={onClose} |         onClose={onClose} | ||||||
|       > |       > | ||||||
|         <Box display="inline-block" w="100%"> |         <Box display="inline-block" w="100%"> | ||||||
|           {getDevice.data && !getDevice.isFetching ? ( |           {configuration && ( | ||||||
|             <Box maxH="calc(100vh - 250px)" minH="300px" overflowY="auto"> |             <Box maxH="calc(100vh - 250px)" minH="300px" overflowY="auto"> | ||||||
|               <Accordion defaultIndex={0} allowToggle> |               <Accordion defaultIndex={0} allowToggle> | ||||||
|                 <AccordionItem> |                 <AccordionItem> | ||||||
| @@ -83,7 +71,7 @@ const ViewConfigurationModal = ({ serialNumber }: { serialNumber: string }) => { | |||||||
|                       enableClipboard={false} |                       enableClipboard={false} | ||||||
|                       theme={colorMode === 'light' ? undefined : 'dark'} |                       theme={colorMode === 'light' ? undefined : 'dark'} | ||||||
|                       defaultInspectDepth={1} |                       defaultInspectDepth={1} | ||||||
|                       value={getDevice.data.configuration as object} |                       value={configuration as object} | ||||||
|                       style={{ background: 'unset', display: 'unset' }} |                       style={{ background: 'unset', display: 'unset' }} | ||||||
|                     /> |                     /> | ||||||
|                   </AccordionPanel> |                   </AccordionPanel> | ||||||
| @@ -98,15 +86,11 @@ const ViewConfigurationModal = ({ serialNumber }: { serialNumber: string }) => { | |||||||
|                     </AccordionButton> |                     </AccordionButton> | ||||||
|                   </h2> |                   </h2> | ||||||
|                   <AccordionPanel pb={4} overflowX="auto"> |                   <AccordionPanel pb={4} overflowX="auto"> | ||||||
|                     <pre>{JSON.stringify(getDevice.data.configuration, null, 2)}</pre> |                     <pre>{JSON.stringify(configuration, null, 2)}</pre> | ||||||
|                   </AccordionPanel> |                   </AccordionPanel> | ||||||
|                 </AccordionItem> |                 </AccordionItem> | ||||||
|               </Accordion> |               </Accordion> | ||||||
|             </Box> |             </Box> | ||||||
|           ) : ( |  | ||||||
|             <Center my={12}> |  | ||||||
|               <Spinner size="xl" /> |  | ||||||
|             </Center> |  | ||||||
|           )} |           )} | ||||||
|         </Box> |         </Box> | ||||||
|       </Modal> |       </Modal> | ||||||
| @@ -114,4 +98,4 @@ const ViewConfigurationModal = ({ serialNumber }: { serialNumber: string }) => { | |||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export default React.memo(ViewConfigurationModal); | export default ViewConfigurationModal; | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ import { ColumnPicker } from 'components/DataTables/ColumnPicker'; | |||||||
| import { DataTable } from 'components/DataTables/DataTable'; | import { DataTable } from 'components/DataTables/DataTable'; | ||||||
| import DataCell from 'components/TableCells/DataCell'; | import DataCell from 'components/TableCells/DataCell'; | ||||||
| import { Column } from 'models/Table'; | import { Column } from 'models/Table'; | ||||||
| import IpCell from './IpCell'; |  | ||||||
|  |  | ||||||
| export type ParsedAssociation = { | export type ParsedAssociation = { | ||||||
|   radio?: ParsedRadio; |   radio?: ParsedRadio; | ||||||
| @@ -36,7 +35,7 @@ type Props = { | |||||||
|   isSingle?: boolean; |   isSingle?: boolean; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const WifiAnalysisAssociationsTable = ({ data, ouis, isSingle }: Props) => { | const WifiAnalysisAssocationsTable = ({ data, ouis, isSingle }: Props) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const [hiddenColumns, setHiddenColumns] = React.useState<string[]>([]); |   const [hiddenColumns, setHiddenColumns] = React.useState<string[]>([]); | ||||||
|  |  | ||||||
| @@ -51,10 +50,6 @@ const WifiAnalysisAssociationsTable = ({ data, ouis, isSingle }: Props) => { | |||||||
|   ); |   ); | ||||||
|   const dataCell = React.useCallback((v: number) => <DataCell bytes={v} />, []); |   const dataCell = React.useCallback((v: number) => <DataCell bytes={v} />, []); | ||||||
|   const indexCell = React.useCallback((assoc: ParsedAssociation) => assoc.radio?.band ?? assoc.radio?.deductedBand, []); |   const indexCell = React.useCallback((assoc: ParsedAssociation) => assoc.radio?.band ?? assoc.radio?.deductedBand, []); | ||||||
|   const ipCell = React.useCallback( |  | ||||||
|     (assoc: ParsedAssociation) => <IpCell ipv4={assoc.ips.ipv4} ipv6={assoc.ips.ipv6} />, |  | ||||||
|     [], |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   const columns: Column<ParsedAssociation>[] = React.useMemo( |   const columns: Column<ParsedAssociation>[] = React.useMemo( | ||||||
|     (): Column<ParsedAssociation>[] => [ |     (): Column<ParsedAssociation>[] => [ | ||||||
| @@ -77,13 +72,6 @@ const WifiAnalysisAssociationsTable = ({ data, ouis, isSingle }: Props) => { | |||||||
|         isMonospace: true, |         isMonospace: true, | ||||||
|         alwaysShow: true, |         alwaysShow: true, | ||||||
|       }, |       }, | ||||||
|       { |  | ||||||
|         id: 'ips', |  | ||||||
|         Header: 'IPs', |  | ||||||
|         Footer: '', |  | ||||||
|         Cell: (v) => ipCell(v.cell.row.original), |  | ||||||
|         disableSortBy: true, |  | ||||||
|       }, |  | ||||||
|       { |       { | ||||||
|         id: 'vendor', |         id: 'vendor', | ||||||
|         Header: t('controller.wifi.vendor'), |         Header: t('controller.wifi.vendor'), | ||||||
| @@ -207,4 +195,4 @@ const WifiAnalysisAssociationsTable = ({ data, ouis, isSingle }: Props) => { | |||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export default WifiAnalysisAssociationsTable; | export default WifiAnalysisAssocationsTable; | ||||||
|   | |||||||
| @@ -1,90 +0,0 @@ | |||||||
| import * as React from 'react'; |  | ||||||
| import { CopyIcon } from '@chakra-ui/icons'; |  | ||||||
| import { |  | ||||||
|   Button, |  | ||||||
|   Flex, |  | ||||||
|   Heading, |  | ||||||
|   IconButton, |  | ||||||
|   ListItem, |  | ||||||
|   Popover, |  | ||||||
|   PopoverArrow, |  | ||||||
|   PopoverBody, |  | ||||||
|   PopoverCloseButton, |  | ||||||
|   PopoverContent, |  | ||||||
|   PopoverHeader, |  | ||||||
|   PopoverTrigger, |  | ||||||
|   Text, |  | ||||||
|   Tooltip, |  | ||||||
|   UnorderedList, |  | ||||||
|   useBoolean, |  | ||||||
|   useClipboard, |  | ||||||
| } from '@chakra-ui/react'; |  | ||||||
|  |  | ||||||
| const CopyString = ({ str }: { str: string }) => { |  | ||||||
|   const [isHovered, setHovered] = useBoolean(false); |  | ||||||
|   const copy = useClipboard(str); |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <Flex alignItems="center" onMouseEnter={setHovered.on} onMouseLeave={setHovered.off}> |  | ||||||
|       <Text>{str}</Text> |  | ||||||
|       <Tooltip label={copy.hasCopied ? 'Copied!' : 'Copy'} placement="top"> |  | ||||||
|         <IconButton |  | ||||||
|           aria-label={copy.hasCopied ? 'Copied!' : 'Copy'} |  | ||||||
|           size="sm" |  | ||||||
|           onClick={copy.onCopy} |  | ||||||
|           icon={<CopyIcon />} |  | ||||||
|           variant="transparent" |  | ||||||
|           opacity={!isHovered ? 0 : 1} |  | ||||||
|         /> |  | ||||||
|       </Tooltip> |  | ||||||
|     </Flex> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| type Props = { |  | ||||||
|   ipv4: string[]; |  | ||||||
|   ipv6: string[]; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const IpCell = ({ ipv4, ipv6 }: Props) => { |  | ||||||
|   const length = ipv4.length + ipv6.length; |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <Popover> |  | ||||||
|       <PopoverTrigger> |  | ||||||
|         <Button colorScheme="teal" size="sm"> |  | ||||||
|           {length} |  | ||||||
|         </Button> |  | ||||||
|       </PopoverTrigger> |  | ||||||
|       <PopoverContent> |  | ||||||
|         <PopoverArrow /> |  | ||||||
|         <PopoverCloseButton /> |  | ||||||
|         <PopoverHeader> |  | ||||||
|           <Heading size="sm"> |  | ||||||
|             {length} {length === 1 ? 'IP' : 'IPs'} |  | ||||||
|           </Heading> |  | ||||||
|         </PopoverHeader> |  | ||||||
|         <PopoverBody> |  | ||||||
|           <Heading size="sm">IpV4 ({ipv4.length})</Heading> |  | ||||||
|           <UnorderedList> |  | ||||||
|             {ipv4.map((ip) => ( |  | ||||||
|               <ListItem key={ip}> |  | ||||||
|                 <CopyString str={ip} /> |  | ||||||
|               </ListItem> |  | ||||||
|             ))} |  | ||||||
|           </UnorderedList> |  | ||||||
|           <Heading size="sm">IpV6 ({ipv6.length})</Heading> |  | ||||||
|           <UnorderedList> |  | ||||||
|             {ipv6.map((ip) => ( |  | ||||||
|               <ListItem key={ip}> |  | ||||||
|                 <CopyString str={ip} /> |  | ||||||
|               </ListItem> |  | ||||||
|             ))} |  | ||||||
|           </UnorderedList> |  | ||||||
|         </PopoverBody> |  | ||||||
|       </PopoverContent> |  | ||||||
|     </Popover> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export default IpCell; |  | ||||||
| @@ -162,7 +162,7 @@ const WifiAnalysisCard = ({ serialNumber }: Props) => { | |||||||
|             <SliderTrack> |             <SliderTrack> | ||||||
|               <SliderFilledTrack /> |               <SliderFilledTrack /> | ||||||
|             </SliderTrack> |             </SliderTrack> | ||||||
|             <SliderThumb zIndex={0} /> |             <SliderThumb /> | ||||||
|           </Slider> |           </Slider> | ||||||
|         )} |         )} | ||||||
|         <Box /> |         <Box /> | ||||||
|   | |||||||
| @@ -694,7 +694,7 @@ const DeviceListCard = () => { | |||||||
|       <DataGrid<DeviceWithStatus> |       <DataGrid<DeviceWithStatus> | ||||||
|         controller={tableController} |         controller={tableController} | ||||||
|         header={{ |         header={{ | ||||||
|           title: `${getCount.data?.count ?? 0} ${t('devices.title')}`, |           title: `${getCount.data?.count} ${t('devices.title')}`, | ||||||
|           objectListed: t('devices.title'), |           objectListed: t('devices.title'), | ||||||
|           leftContent: <GlobalSearchBar />, |           leftContent: <GlobalSearchBar />, | ||||||
|           otherButtons: ( |           otherButtons: ( | ||||||
|   | |||||||
| @@ -138,7 +138,6 @@ const FirmwareDetailsModal = ({ modalProps, firmware }: Props) => { | |||||||
|  |  | ||||||
|   React.useEffect(() => { |   React.useEffect(() => { | ||||||
|     if (firmware) { |     if (firmware) { | ||||||
|       copy.setValue(firmware?.uri ?? ''); |  | ||||||
|       setNewDescription(firmware?.description); |       setNewDescription(firmware?.description); | ||||||
|     } |     } | ||||||
|   }, [firmware]); |   }, [firmware]); | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ import React from 'react'; | |||||||
| import { Barcode, FloppyDisk, Info, ListBullets, TerminalWindow, UsersThree, WifiHigh } from '@phosphor-icons/react'; | import { Barcode, FloppyDisk, Info, ListBullets, TerminalWindow, UsersThree, WifiHigh } from '@phosphor-icons/react'; | ||||||
| import { Route } from 'models/Routes'; | import { Route } from 'models/Routes'; | ||||||
|  |  | ||||||
| const AdvancedSystemPage = React.lazy(() => import('pages/AdvancedSystemPage')); |  | ||||||
| const DefaultConfigurationsPage = React.lazy(() => import('pages/DefaultConfigurations')); | const DefaultConfigurationsPage = React.lazy(() => import('pages/DefaultConfigurations')); | ||||||
| const DefaultFirmwarePage = React.lazy(() => import('pages/DefaultFirmware')); | const DefaultFirmwarePage = React.lazy(() => import('pages/DefaultFirmware')); | ||||||
| const DevicePage = React.lazy(() => import('pages/Device')); | const DevicePage = React.lazy(() => import('pages/Device')); | ||||||
| @@ -179,13 +178,6 @@ const routes: Route[] = [ | |||||||
|     name: 'system.title', |     name: 'system.title', | ||||||
|     icon: () => <Info size={28} weight="bold" />, |     icon: () => <Info size={28} weight="bold" />, | ||||||
|     children: [ |     children: [ | ||||||
|       { |  | ||||||
|         id: 'system-advanced', |  | ||||||
|         authorized: ['root', 'partner', 'admin', 'csr', 'system'], |  | ||||||
|         path: '/systemAdvanced', |  | ||||||
|         name: 'system.advanced', |  | ||||||
|         component: AdvancedSystemPage, |  | ||||||
|       }, |  | ||||||
|       { |       { | ||||||
|         id: 'system-configuration', |         id: 'system-configuration', | ||||||
|         authorized: ['root', 'partner', 'admin', 'csr', 'system'], |         authorized: ['root', 'partner', 'admin', 'csr', 'system'], | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user