mirror of
				https://github.com/optim-enterprises-bv/OptimCloud-gw-ui.git
				synced 2025-10-29 17:32:20 +00:00 
			
		
		
		
	[WIFI-13170] Advanced system page
Signed-off-by: Charles <charles.bourque96@gmail.com>
This commit is contained in:
		
							
								
								
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,12 +1,12 @@ | |||||||
| { | { | ||||||
|   "name": "ucentral-client", |   "name": "ucentral-client", | ||||||
|   "version": "2.11.0(16)", |   "version": "3.0.0(1)", | ||||||
|   "lockfileVersion": 3, |   "lockfileVersion": 3, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "packages": { |   "packages": { | ||||||
|     "": { |     "": { | ||||||
|       "name": "ucentral-client", |       "name": "ucentral-client", | ||||||
|       "version": "2.11.0(16)", |       "version": "3.0.0(1)", | ||||||
|       "license": "ISC", |       "license": "ISC", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@chakra-ui/anatomy": "^2.1.1", |         "@chakra-ui/anatomy": "^2.1.1", | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "ucentral-client", |   "name": "ucentral-client", | ||||||
|   "version": "2.11.0(16)", |   "version": "3.0.0(1)", | ||||||
|   "description": "", |   "description": "", | ||||||
|   "private": true, |   "private": true, | ||||||
|   "main": "index.tsx", |   "main": "index.tsx", | ||||||
|   | |||||||
| @@ -269,6 +269,7 @@ | |||||||
| 		"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", | ||||||
| @@ -737,6 +738,7 @@ | |||||||
| 	"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", | ||||||
| @@ -763,7 +765,11 @@ | |||||||
| 		"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", | ||||||
| @@ -905,6 +911,11 @@ | |||||||
| 		"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", | ||||||
| @@ -970,6 +981,27 @@ | |||||||
| 		"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", | ||||||
| @@ -1091,6 +1123,7 @@ | |||||||
| 		"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,6 +269,7 @@ | |||||||
| 		"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", | ||||||
| @@ -737,6 +738,7 @@ | |||||||
| 	"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", | ||||||
| @@ -763,7 +765,11 @@ | |||||||
| 		"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", | ||||||
| @@ -905,6 +911,11 @@ | |||||||
| 		"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", | ||||||
| @@ -970,6 +981,27 @@ | |||||||
| 		"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", | ||||||
| @@ -1091,6 +1123,7 @@ | |||||||
| 		"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,6 +269,7 @@ | |||||||
| 		"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", | ||||||
| @@ -737,6 +738,7 @@ | |||||||
| 	"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", | ||||||
| @@ -763,7 +765,11 @@ | |||||||
| 		"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", | ||||||
| @@ -905,6 +911,11 @@ | |||||||
| 		"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", | ||||||
| @@ -970,6 +981,27 @@ | |||||||
| 		"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", | ||||||
| @@ -1091,6 +1123,7 @@ | |||||||
| 		"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,6 +269,7 @@ | |||||||
| 		"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é", | ||||||
| @@ -737,6 +738,7 @@ | |||||||
| 	"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", | ||||||
| @@ -763,7 +765,11 @@ | |||||||
| 		"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", | ||||||
| @@ -905,6 +911,11 @@ | |||||||
| 		"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", | ||||||
| @@ -970,6 +981,27 @@ | |||||||
| 		"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", | ||||||
| @@ -1091,6 +1123,7 @@ | |||||||
| 		"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,6 +269,7 @@ | |||||||
| 		"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", | ||||||
| @@ -737,6 +738,7 @@ | |||||||
| 	"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", | ||||||
| @@ -763,7 +765,11 @@ | |||||||
| 		"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", | ||||||
| @@ -905,6 +911,11 @@ | |||||||
| 		"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", | ||||||
| @@ -970,6 +981,27 @@ | |||||||
| 		"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", | ||||||
| @@ -1091,6 +1123,7 @@ | |||||||
| 		"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", | ||||||
|   | |||||||
							
								
								
									
										173
									
								
								src/hooks/Network/Simulations.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								src/hooks/Network/Simulations.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | |||||||
|  | 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']); | ||||||
|  |     }, | ||||||
|  |   }); | ||||||
|  | }; | ||||||
							
								
								
									
										80
									
								
								src/hooks/useNotification.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/hooks/useNotification.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | |||||||
|  | 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>; | ||||||
| @@ -1,3 +1,6 @@ | |||||||
| import { AxiosError as Err } from 'axios'; | import { AxiosError as Err, isAxiosError } 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; | ||||||
|   | |||||||
							
								
								
									
										93
									
								
								src/pages/AdvancedSystemPage/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/pages/AdvancedSystemPage/index.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | 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; | ||||||
| @@ -2,6 +2,7 @@ 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')); | ||||||
| @@ -178,6 +179,13 @@ 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
	 Charles
					Charles