Compare commits

..

2 Commits

Author SHA1 Message Date
TIP Automation User
8d8b1e3945 Chg: update image tag in helm values to v2.11.0 2023-10-04 14:03:38 +00:00
TIP Automation User
c869b5c077 Chg: update image tag in helm values to v2.11.0-RC1 2023-09-01 16:08:55 +00:00
33 changed files with 220 additions and 1008 deletions

1
.gitignore vendored
View File

@@ -18,4 +18,3 @@
.env.production.local .env.production.local
npm-debug.log* npm-debug.log*
.vscode/settings.json

View File

@@ -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
View File

@@ -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"
}, },

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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}} ",

View File

@@ -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}} ",

View File

@@ -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",

View File

@@ -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;
}; };

View File

@@ -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>

View File

@@ -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"

View File

@@ -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} />

View File

@@ -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([]);
}, },

View File

@@ -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);

View File

@@ -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>
); );

View File

@@ -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>
</> </>
); );
}; };

View File

@@ -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',
});
}
}, },
}); });
}; };

View File

@@ -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']);
},
});
};

View File

@@ -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>;

View File

@@ -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%"

View File

@@ -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;

View File

@@ -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[];

View File

@@ -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;

View File

@@ -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%">

View File

@@ -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>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -162,7 +162,7 @@ const WifiAnalysisCard = ({ serialNumber }: Props) => {
<SliderTrack> <SliderTrack>
<SliderFilledTrack /> <SliderFilledTrack />
</SliderTrack> </SliderTrack>
<SliderThumb zIndex={0} /> <SliderThumb />
</Slider> </Slider>
)} )}
<Box /> <Box />

View File

@@ -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: (

View File

@@ -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]);

View File

@@ -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'],