mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui.git
synced 2025-11-01 19:27:58 +00:00
UI fixes, standardization
This commit is contained in:
@@ -4,6 +4,7 @@ const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
|||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const webpack = require('webpack');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const paths = require('./paths');
|
const paths = require('./paths');
|
||||||
|
|
||||||
@@ -19,6 +20,9 @@ module.exports = {
|
|||||||
preferRelative: true,
|
preferRelative: true,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.VERSION': JSON.stringify(process.env.npm_package_version),
|
||||||
|
}),
|
||||||
new MiniCssExtractPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: 'styles/[name].[contenthash].css',
|
filename: 'styles/[name].[contenthash].css',
|
||||||
chunkFilename: '[id].[contenthash].css',
|
chunkFilename: '[id].[contenthash].css',
|
||||||
|
|||||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.1.10",
|
"version": "2.1.12",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.1.10",
|
"version": "2.1.12",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@coreui/coreui": "^3.4.0",
|
"@coreui/coreui": "^3.4.0",
|
||||||
"@coreui/icons": "^2.0.1",
|
"@coreui/icons": "^2.0.1",
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"react-tooltip": "^4.2.21",
|
"react-tooltip": "^4.2.21",
|
||||||
"react-widgets": "^5.1.1",
|
"react-widgets": "^5.1.1",
|
||||||
"sass": "^1.35.1",
|
"sass": "^1.35.1",
|
||||||
"ucentral-libs": "^0.9.17",
|
"ucentral-libs": "^0.9.18",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -14812,9 +14812,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ucentral-libs": {
|
"node_modules/ucentral-libs": {
|
||||||
"version": "0.9.17",
|
"version": "0.9.18",
|
||||||
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.9.17.tgz",
|
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.9.18.tgz",
|
||||||
"integrity": "sha512-GQtEaOhdFcBmNeu4NhYiq4yVsycZ7i8DeotubcKN8lt9v/TjAPecle0FsDdiXgXphOblToym6mk2tCAbH/958g==",
|
"integrity": "sha512-znLLUdrRdBCYyufpFk/LWMVx0iajbuMTqayxWJek8JJeiaFlgH58+52s1OKjsLEb6Q4kPOIeUHguN3pJ/EfB1w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@coreui/coreui": "^3.4.0",
|
"@coreui/coreui": "^3.4.0",
|
||||||
"@coreui/icons": "^2.0.1",
|
"@coreui/icons": "^2.0.1",
|
||||||
@@ -27653,9 +27653,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ucentral-libs": {
|
"ucentral-libs": {
|
||||||
"version": "0.9.17",
|
"version": "0.9.18",
|
||||||
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.9.17.tgz",
|
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.9.18.tgz",
|
||||||
"integrity": "sha512-GQtEaOhdFcBmNeu4NhYiq4yVsycZ7i8DeotubcKN8lt9v/TjAPecle0FsDdiXgXphOblToym6mk2tCAbH/958g==",
|
"integrity": "sha512-znLLUdrRdBCYyufpFk/LWMVx0iajbuMTqayxWJek8JJeiaFlgH58+52s1OKjsLEb6Q4kPOIeUHguN3pJ/EfB1w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@coreui/coreui": "^3.4.0",
|
"@coreui/coreui": "^3.4.0",
|
||||||
"@coreui/icons": "^2.0.1",
|
"@coreui/icons": "^2.0.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.1.10",
|
"version": "2.1.12",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@coreui/coreui": "^3.4.0",
|
"@coreui/coreui": "^3.4.0",
|
||||||
"@coreui/icons": "^2.0.1",
|
"@coreui/icons": "^2.0.1",
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"react-tooltip": "^4.2.21",
|
"react-tooltip": "^4.2.21",
|
||||||
"react-widgets": "^5.1.1",
|
"react-widgets": "^5.1.1",
|
||||||
"sass": "^1.35.1",
|
"sass": "^1.35.1",
|
||||||
"ucentral-libs": "^0.9.17",
|
"ucentral-libs": "^0.9.18",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -23,10 +23,11 @@
|
|||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"error": "Fehler beim Senden des Befehls!",
|
"error": "Fehler beim Senden des Befehls!",
|
||||||
|
"error_delete_log": "Fehler beim Versuch zu löschen: {{error}}",
|
||||||
"event_queue": "Ereigniswarteschlange",
|
"event_queue": "Ereigniswarteschlange",
|
||||||
"success": "Befehl wurde erfolgreich übermittelt",
|
"success": "Befehl wurde erfolgreich übermittelt",
|
||||||
"title": "Gerätebefehle",
|
"title": "Gerätebefehle",
|
||||||
"unable_queue": "Anfrage für Ereigniswarteschlange kann nicht abgeschlossen werden"
|
"unable_queue": "Anfrage für Ereigniswarteschlange kann nicht abgeschlossen werden: {{error}}"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"access_policy": "Zugangsrichtlinien",
|
"access_policy": "Zugangsrichtlinien",
|
||||||
@@ -205,6 +206,9 @@
|
|||||||
"title": "Gerät konfigurieren",
|
"title": "Gerät konfigurieren",
|
||||||
"valid_json": "Sie müssen ein gültiges JSON eingeben"
|
"valid_json": "Sie müssen ein gültiges JSON eingeben"
|
||||||
},
|
},
|
||||||
|
"connect": {
|
||||||
|
"error_trying_to_connect": "Fehler beim Versuch, eine Verbindung zum Gerät herzustellen: {{error}}"
|
||||||
|
},
|
||||||
"delete_command": {
|
"delete_command": {
|
||||||
"explanation": "Möchten Sie diesen Befehl wirklich löschen? Diese Aktion ist nicht umkehrbar.",
|
"explanation": "Möchten Sie diesen Befehl wirklich löschen? Diese Aktion ist nicht umkehrbar.",
|
||||||
"title": "Befehl löschen"
|
"title": "Befehl löschen"
|
||||||
@@ -215,6 +219,10 @@
|
|||||||
"explanation": "Dadurch werden alle {{object}} vor dem von Ihnen gewählten Datum gelöscht. Seien Sie vorsichtig, diese Aktion ist nicht umkehrbar.",
|
"explanation": "Dadurch werden alle {{object}} vor dem von Ihnen gewählten Datum gelöscht. Seien Sie vorsichtig, diese Aktion ist nicht umkehrbar.",
|
||||||
"healthchecks_title": "Healthchecks löschen"
|
"healthchecks_title": "Healthchecks löschen"
|
||||||
},
|
},
|
||||||
|
"device": {
|
||||||
|
"error_fetching_device": "Fehler beim Abrufen der Geräteinformationen: {{error}}",
|
||||||
|
"error_fetching_devices": "Fehler beim Abrufen von Geräten: {{error}}"
|
||||||
|
},
|
||||||
"device_logs": {
|
"device_logs": {
|
||||||
"log": "Protokoll",
|
"log": "Protokoll",
|
||||||
"severity": "Wichtigkeit",
|
"severity": "Wichtigkeit",
|
||||||
@@ -486,7 +494,7 @@
|
|||||||
"create_success": "Benutzer erfolgreich erstellt",
|
"create_success": "Benutzer erfolgreich erstellt",
|
||||||
"creating": "Benutzer erstellen ...",
|
"creating": "Benutzer erstellen ...",
|
||||||
"delete_avatar": "Avatar löschen",
|
"delete_avatar": "Avatar löschen",
|
||||||
"delete_failure": "Fehler beim Versuch, den Benutzer zu löschen",
|
"delete_failure": "Fehler beim Versuch, den Benutzer zu löschen: {{error}}",
|
||||||
"delete_success": "Benutzer erfolgreich gelöscht!",
|
"delete_success": "Benutzer erfolgreich gelöscht!",
|
||||||
"delete_title": "Benutzer löschen",
|
"delete_title": "Benutzer löschen",
|
||||||
"delete_warning": "Warnung: Sobald Sie einen Benutzer gelöscht haben, können Sie ihn nicht wiederherstellen",
|
"delete_warning": "Warnung: Sobald Sie einen Benutzer gelöscht haben, können Sie ihn nicht wiederherstellen",
|
||||||
@@ -494,6 +502,7 @@
|
|||||||
"description": "Beschreibung",
|
"description": "Beschreibung",
|
||||||
"edit": "Benutzer bearbeiten",
|
"edit": "Benutzer bearbeiten",
|
||||||
"email_address": "E-Mail-Addresse",
|
"email_address": "E-Mail-Addresse",
|
||||||
|
"error_fetching_users": "Fehler beim Abrufen der Nutzer: {{error}}",
|
||||||
"force_password_change": "Passwortänderung bei der Anmeldung erzwingen",
|
"force_password_change": "Passwortänderung bei der Anmeldung erzwingen",
|
||||||
"id": "Benutzeridentifikation.",
|
"id": "Benutzeridentifikation.",
|
||||||
"last_login": "Letzte Anmeldung",
|
"last_login": "Letzte Anmeldung",
|
||||||
@@ -509,7 +518,7 @@
|
|||||||
"provide_password": "Bitte geben Sie ein gültiges Passwort ein",
|
"provide_password": "Bitte geben Sie ein gültiges Passwort ein",
|
||||||
"save_avatar": "Avatar speichern",
|
"save_avatar": "Avatar speichern",
|
||||||
"show_hide_password": "Passwort anzeigen/verbergen",
|
"show_hide_password": "Passwort anzeigen/verbergen",
|
||||||
"update_failure": "Stellen Sie sicher, dass alle Ihre Daten gültig sind. Wenn Sie das Kennwort ändern, stellen Sie sicher, dass es sich nicht um ein altes handelt.",
|
"update_failure": "Fehler beim Aktualisieren: {{error}}",
|
||||||
"update_failure_title": "Update fehlgeschlagen",
|
"update_failure_title": "Update fehlgeschlagen",
|
||||||
"update_success": "Benutzer erfolgreich aktualisiert",
|
"update_success": "Benutzer erfolgreich aktualisiert",
|
||||||
"update_success_title": "Erfolg",
|
"update_success_title": "Erfolg",
|
||||||
|
|||||||
@@ -23,10 +23,11 @@
|
|||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"error": "Error while submitting command!",
|
"error": "Error while submitting command!",
|
||||||
|
"error_delete_log": "Error while trying to delete: {{error}}",
|
||||||
"event_queue": "Event Queue",
|
"event_queue": "Event Queue",
|
||||||
"success": "Command submitted successfully, you can look at the Commands log for the result",
|
"success": "Command submitted successfully, you can look at the Commands log for the result",
|
||||||
"title": "Command History",
|
"title": "Command History",
|
||||||
"unable_queue": "Unable to complete event queue request"
|
"unable_queue": "Unable to complete event queue request: {{error}}"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"access_policy": "Access Policy",
|
"access_policy": "Access Policy",
|
||||||
@@ -205,6 +206,9 @@
|
|||||||
"title": "Configure",
|
"title": "Configure",
|
||||||
"valid_json": "You need to enter valid JSON"
|
"valid_json": "You need to enter valid JSON"
|
||||||
},
|
},
|
||||||
|
"connect": {
|
||||||
|
"error_trying_to_connect": "Error while trying to connect to device: {{error}}"
|
||||||
|
},
|
||||||
"delete_command": {
|
"delete_command": {
|
||||||
"explanation": "Are you sure you want to delete this command? This action is not reversible.",
|
"explanation": "Are you sure you want to delete this command? This action is not reversible.",
|
||||||
"title": "Delete Command"
|
"title": "Delete Command"
|
||||||
@@ -215,6 +219,10 @@
|
|||||||
"explanation": "This will delete all of the {{object}} before the date you choose. Be careful, this action is not reversible.",
|
"explanation": "This will delete all of the {{object}} before the date you choose. Be careful, this action is not reversible.",
|
||||||
"healthchecks_title": "Delete Healthchecks"
|
"healthchecks_title": "Delete Healthchecks"
|
||||||
},
|
},
|
||||||
|
"device": {
|
||||||
|
"error_fetching_device": "Error fetching device information: {{error}}",
|
||||||
|
"error_fetching_devices": "Error while fetching devices: {{error}}"
|
||||||
|
},
|
||||||
"device_logs": {
|
"device_logs": {
|
||||||
"log": "Log",
|
"log": "Log",
|
||||||
"severity": "Severity",
|
"severity": "Severity",
|
||||||
@@ -486,7 +494,7 @@
|
|||||||
"create_success": "User Created Successfully",
|
"create_success": "User Created Successfully",
|
||||||
"creating": "Creating User...",
|
"creating": "Creating User...",
|
||||||
"delete_avatar": "Delete Avatar",
|
"delete_avatar": "Delete Avatar",
|
||||||
"delete_failure": "Error while trying to delete user",
|
"delete_failure": "Error while trying to delete user: {{error}}",
|
||||||
"delete_success": "User successfully deleted!",
|
"delete_success": "User successfully deleted!",
|
||||||
"delete_title": "Delete User",
|
"delete_title": "Delete User",
|
||||||
"delete_warning": "Warning: Once you delete a user you cannot revert",
|
"delete_warning": "Warning: Once you delete a user you cannot revert",
|
||||||
@@ -494,6 +502,7 @@
|
|||||||
"description": "Description",
|
"description": "Description",
|
||||||
"edit": "Edit User",
|
"edit": "Edit User",
|
||||||
"email_address": "Email Address",
|
"email_address": "Email Address",
|
||||||
|
"error_fetching_users": "Error fetching users: {{error}}",
|
||||||
"force_password_change": "Force Password Change on Login",
|
"force_password_change": "Force Password Change on Login",
|
||||||
"id": "User Id.",
|
"id": "User Id.",
|
||||||
"last_login": "Last Login",
|
"last_login": "Last Login",
|
||||||
@@ -509,7 +518,7 @@
|
|||||||
"provide_password": "Please provide a valid password",
|
"provide_password": "Please provide a valid password",
|
||||||
"save_avatar": "Save Avatar",
|
"save_avatar": "Save Avatar",
|
||||||
"show_hide_password": "Show/Hide Password",
|
"show_hide_password": "Show/Hide Password",
|
||||||
"update_failure": "Make sure all of your data is valid. If you are modifying the password, make sure it is not an old one.",
|
"update_failure": "Error while trying to update: {{error}}",
|
||||||
"update_failure_title": "Update Failed",
|
"update_failure_title": "Update Failed",
|
||||||
"update_success": "User Updated Successfully",
|
"update_success": "User Updated Successfully",
|
||||||
"update_success_title": "Success",
|
"update_success_title": "Success",
|
||||||
|
|||||||
@@ -23,10 +23,11 @@
|
|||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"error": "¡Error al enviar el comando!",
|
"error": "¡Error al enviar el comando!",
|
||||||
|
"error_delete_log": "Error al intentar eliminar: {{error}}",
|
||||||
"event_queue": "Cola de eventos",
|
"event_queue": "Cola de eventos",
|
||||||
"success": "Comando enviado con éxito, puede consultar el registro de Comandos para ver el resultado",
|
"success": "Comando enviado con éxito, puede consultar el registro de Comandos para ver el resultado",
|
||||||
"title": "Historial de Comandos",
|
"title": "Historial de Comandos",
|
||||||
"unable_queue": "No se pudo completar la solicitud de cola de eventos"
|
"unable_queue": "No se pudo completar la solicitud de cola de eventos: {{error}}"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"access_policy": "Política de acceso",
|
"access_policy": "Política de acceso",
|
||||||
@@ -205,6 +206,9 @@
|
|||||||
"title": "Configurar",
|
"title": "Configurar",
|
||||||
"valid_json": "Debes ingresar un JSON válido"
|
"valid_json": "Debes ingresar un JSON válido"
|
||||||
},
|
},
|
||||||
|
"connect": {
|
||||||
|
"error_trying_to_connect": "Error al intentar conectarse al dispositivo: {{error}}"
|
||||||
|
},
|
||||||
"delete_command": {
|
"delete_command": {
|
||||||
"explanation": "¿Está seguro de que desea eliminar este comando? Esta acción no es reversible.",
|
"explanation": "¿Está seguro de que desea eliminar este comando? Esta acción no es reversible.",
|
||||||
"title": "Eliminar comando"
|
"title": "Eliminar comando"
|
||||||
@@ -215,6 +219,10 @@
|
|||||||
"explanation": "Esto eliminará todos los {{object}} antes de la fecha que elija. Tenga cuidado, esta acción no es reversible.",
|
"explanation": "Esto eliminará todos los {{object}} antes de la fecha que elija. Tenga cuidado, esta acción no es reversible.",
|
||||||
"healthchecks_title": "Eliminar comprobaciones de estado"
|
"healthchecks_title": "Eliminar comprobaciones de estado"
|
||||||
},
|
},
|
||||||
|
"device": {
|
||||||
|
"error_fetching_device": "Error al obtener la información del dispositivo: {{error}}",
|
||||||
|
"error_fetching_devices": "Error al recuperar dispositivos: {{error}}"
|
||||||
|
},
|
||||||
"device_logs": {
|
"device_logs": {
|
||||||
"log": "Iniciar sesión",
|
"log": "Iniciar sesión",
|
||||||
"severity": "Gravedad",
|
"severity": "Gravedad",
|
||||||
@@ -486,7 +494,7 @@
|
|||||||
"create_success": "Usuario creado con éxito",
|
"create_success": "Usuario creado con éxito",
|
||||||
"creating": "Creando usuario ...",
|
"creating": "Creando usuario ...",
|
||||||
"delete_avatar": "Eliminar avatar",
|
"delete_avatar": "Eliminar avatar",
|
||||||
"delete_failure": "Error al intentar eliminar al usuario",
|
"delete_failure": "Error al intentar eliminar al usuario: {{error}}",
|
||||||
"delete_success": "¡Usuario eliminado correctamente!",
|
"delete_success": "¡Usuario eliminado correctamente!",
|
||||||
"delete_title": "Borrar usuario",
|
"delete_title": "Borrar usuario",
|
||||||
"delete_warning": "Advertencia: una vez que elimina un usuario, no puede revertir",
|
"delete_warning": "Advertencia: una vez que elimina un usuario, no puede revertir",
|
||||||
@@ -494,6 +502,7 @@
|
|||||||
"description": "Descripción",
|
"description": "Descripción",
|
||||||
"edit": "editar usuario",
|
"edit": "editar usuario",
|
||||||
"email_address": "Dirección de correo electrónico",
|
"email_address": "Dirección de correo electrónico",
|
||||||
|
"error_fetching_users": "Error al obtener usuarios: {{error}}",
|
||||||
"force_password_change": "Forzar cambio de contraseña al iniciar sesión",
|
"force_password_change": "Forzar cambio de contraseña al iniciar sesión",
|
||||||
"id": "Id. De usuario",
|
"id": "Id. De usuario",
|
||||||
"last_login": "Último acceso",
|
"last_login": "Último acceso",
|
||||||
@@ -509,7 +518,7 @@
|
|||||||
"provide_password": "Proporcione una contraseña válida",
|
"provide_password": "Proporcione una contraseña válida",
|
||||||
"save_avatar": "Guardar avatar",
|
"save_avatar": "Guardar avatar",
|
||||||
"show_hide_password": "Mostrar / Ocultar contraseña",
|
"show_hide_password": "Mostrar / Ocultar contraseña",
|
||||||
"update_failure": "Asegúrese de que todos sus datos sean válidos. Si está modificando la contraseña, asegúrese de que no sea antigua.",
|
"update_failure": "Error al intentar actualizar: {{error}}",
|
||||||
"update_failure_title": "Actualización fallida",
|
"update_failure_title": "Actualización fallida",
|
||||||
"update_success": "Usuario actualizado con éxito",
|
"update_success": "Usuario actualizado con éxito",
|
||||||
"update_success_title": "Éxito",
|
"update_success_title": "Éxito",
|
||||||
|
|||||||
@@ -23,10 +23,11 @@
|
|||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"error": "Erreur lors de la soumission de la commande !",
|
"error": "Erreur lors de la soumission de la commande !",
|
||||||
|
"error_delete_log": "Erreur lors de la tentative de suppression : {{error}}",
|
||||||
"event_queue": "File d'attente d'événements",
|
"event_queue": "File d'attente d'événements",
|
||||||
"success": "Commande soumise avec succès, vous pouvez consulter le journal des commandes pour le résultat",
|
"success": "Commande soumise avec succès, vous pouvez consulter le journal des commandes pour le résultat",
|
||||||
"title": "Historique des commandes",
|
"title": "Historique des commandes",
|
||||||
"unable_queue": "Impossible de terminer la demande de file d'attente d'événements"
|
"unable_queue": "Impossible de terminer la demande de file d'attente d'événements: {{error}}"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"access_policy": "Politique d'accès",
|
"access_policy": "Politique d'accès",
|
||||||
@@ -205,6 +206,9 @@
|
|||||||
"title": "Configurer",
|
"title": "Configurer",
|
||||||
"valid_json": "Vous devez entrer un JSON valide"
|
"valid_json": "Vous devez entrer un JSON valide"
|
||||||
},
|
},
|
||||||
|
"connect": {
|
||||||
|
"error_trying_to_connect": "Erreur lors de la tentative de connexion à l'appareil : {{error}}"
|
||||||
|
},
|
||||||
"delete_command": {
|
"delete_command": {
|
||||||
"explanation": "Êtes-vous sûr de vouloir supprimer cette commande ? Cette action n'est pas réversible.",
|
"explanation": "Êtes-vous sûr de vouloir supprimer cette commande ? Cette action n'est pas réversible.",
|
||||||
"title": "Supprimer la commande"
|
"title": "Supprimer la commande"
|
||||||
@@ -215,6 +219,10 @@
|
|||||||
"explanation": "Cela supprimera tous les {{object}} avant la date que vous choisissez. Attention, cette action n'est pas réversible.",
|
"explanation": "Cela supprimera tous les {{object}} avant la date que vous choisissez. Attention, cette action n'est pas réversible.",
|
||||||
"healthchecks_title": "Supprimer les vérifications d'état"
|
"healthchecks_title": "Supprimer les vérifications d'état"
|
||||||
},
|
},
|
||||||
|
"device": {
|
||||||
|
"error_fetching_device": "Erreur lors de la récupération des informations sur l'appareil : {{error}}",
|
||||||
|
"error_fetching_devices": "Erreur lors de la récupération des appareils : {{error}}"
|
||||||
|
},
|
||||||
"device_logs": {
|
"device_logs": {
|
||||||
"log": "Bûche",
|
"log": "Bûche",
|
||||||
"severity": "Gravité",
|
"severity": "Gravité",
|
||||||
@@ -486,7 +494,7 @@
|
|||||||
"create_success": "L'utilisateur a été créé avec succès",
|
"create_success": "L'utilisateur a été créé avec succès",
|
||||||
"creating": "Création de l'utilisateur...",
|
"creating": "Création de l'utilisateur...",
|
||||||
"delete_avatar": "Supprimer l'avatar",
|
"delete_avatar": "Supprimer l'avatar",
|
||||||
"delete_failure": "Erreur lors de la tentative de suppression de l'utilisateur",
|
"delete_failure": "Erreur lors de la tentative de suppression de l'utilisateur: {{error}}",
|
||||||
"delete_success": "Utilisateur supprimé avec succès !",
|
"delete_success": "Utilisateur supprimé avec succès !",
|
||||||
"delete_title": "Supprimer l'utilisateur",
|
"delete_title": "Supprimer l'utilisateur",
|
||||||
"delete_warning": "Avertissement : Une fois que vous avez supprimé un utilisateur, vous ne pouvez plus revenir en arrière",
|
"delete_warning": "Avertissement : Une fois que vous avez supprimé un utilisateur, vous ne pouvez plus revenir en arrière",
|
||||||
@@ -494,6 +502,7 @@
|
|||||||
"description": "La description",
|
"description": "La description",
|
||||||
"edit": "Modifier l'utilisateur",
|
"edit": "Modifier l'utilisateur",
|
||||||
"email_address": "Adresse électronique",
|
"email_address": "Adresse électronique",
|
||||||
|
"error_fetching_users": "Erreur lors de la récupération des utilisateurs : {{error}}",
|
||||||
"force_password_change": "Forcer le changement de mot de passe lors de la connexion",
|
"force_password_change": "Forcer le changement de mot de passe lors de la connexion",
|
||||||
"id": "Identifiant d'utilisateur.",
|
"id": "Identifiant d'utilisateur.",
|
||||||
"last_login": "Dernière connexion",
|
"last_login": "Dernière connexion",
|
||||||
@@ -509,7 +518,7 @@
|
|||||||
"provide_password": "Veuillez fournir un mot de passe valide",
|
"provide_password": "Veuillez fournir un mot de passe valide",
|
||||||
"save_avatar": "Enregistrer l'avatar",
|
"save_avatar": "Enregistrer l'avatar",
|
||||||
"show_hide_password": "Afficher/Masquer le mot de passe",
|
"show_hide_password": "Afficher/Masquer le mot de passe",
|
||||||
"update_failure": "Assurez-vous que toutes vos données sont valides. Si vous modifiez le mot de passe, assurez-vous qu'il ne s'agit pas d'un ancien.",
|
"update_failure": "Erreur lors de la tentative de mise à jour : {{error}}",
|
||||||
"update_failure_title": "mise à jour a échoué",
|
"update_failure_title": "mise à jour a échoué",
|
||||||
"update_success": "L'utilisateur a bien été mis à jour",
|
"update_success": "L'utilisateur a bien été mis à jour",
|
||||||
"update_success_title": "Succès",
|
"update_success_title": "Succès",
|
||||||
|
|||||||
@@ -23,10 +23,11 @@
|
|||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"error": "Erro ao enviar comando!",
|
"error": "Erro ao enviar comando!",
|
||||||
|
"error_delete_log": "Erro ao tentar excluir: {{error}}",
|
||||||
"event_queue": "Fila de Eventos",
|
"event_queue": "Fila de Eventos",
|
||||||
"success": "Comando enviado com sucesso, você pode consultar o log de Comandos para ver o resultado",
|
"success": "Comando enviado com sucesso, você pode consultar o log de Comandos para ver o resultado",
|
||||||
"title": "Histórico de Comandos",
|
"title": "Histórico de Comandos",
|
||||||
"unable_queue": "Incapaz de completar o pedido de fila de eventos"
|
"unable_queue": "Incapaz de completar o pedido de fila de eventos: {{error}}"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"access_policy": "Política de Acesso",
|
"access_policy": "Política de Acesso",
|
||||||
@@ -205,6 +206,9 @@
|
|||||||
"title": "Configurar",
|
"title": "Configurar",
|
||||||
"valid_json": "Você precisa inserir um JSON válido"
|
"valid_json": "Você precisa inserir um JSON válido"
|
||||||
},
|
},
|
||||||
|
"connect": {
|
||||||
|
"error_trying_to_connect": "Erro ao tentar conectar ao dispositivo: {{error}}"
|
||||||
|
},
|
||||||
"delete_command": {
|
"delete_command": {
|
||||||
"explanation": "Tem certeza de que deseja excluir este comando? esta ação não é reversível.",
|
"explanation": "Tem certeza de que deseja excluir este comando? esta ação não é reversível.",
|
||||||
"title": "Apagar Comando"
|
"title": "Apagar Comando"
|
||||||
@@ -215,6 +219,10 @@
|
|||||||
"explanation": "Isso excluirá todos os {{object}} antes da data que você escolheu. Cuidado, esta ação não é reversível.",
|
"explanation": "Isso excluirá todos os {{object}} antes da data que você escolheu. Cuidado, esta ação não é reversível.",
|
||||||
"healthchecks_title": "Excluir verificações de saúde"
|
"healthchecks_title": "Excluir verificações de saúde"
|
||||||
},
|
},
|
||||||
|
"device": {
|
||||||
|
"error_fetching_device": "Erro ao buscar informações do dispositivo: {{error}}",
|
||||||
|
"error_fetching_devices": "Erro ao buscar dispositivos: {{error}}"
|
||||||
|
},
|
||||||
"device_logs": {
|
"device_logs": {
|
||||||
"log": "Registro",
|
"log": "Registro",
|
||||||
"severity": "Gravidade",
|
"severity": "Gravidade",
|
||||||
@@ -486,7 +494,7 @@
|
|||||||
"create_success": "Usuário criado com sucesso",
|
"create_success": "Usuário criado com sucesso",
|
||||||
"creating": "Criando usuário ...",
|
"creating": "Criando usuário ...",
|
||||||
"delete_avatar": "Apagar Avatar",
|
"delete_avatar": "Apagar Avatar",
|
||||||
"delete_failure": "Erro ao tentar excluir usuário",
|
"delete_failure": "Erro ao tentar excluir usuário: {{error}}",
|
||||||
"delete_success": "Usuário excluído com sucesso!",
|
"delete_success": "Usuário excluído com sucesso!",
|
||||||
"delete_title": "Deletar usuário",
|
"delete_title": "Deletar usuário",
|
||||||
"delete_warning": "Aviso: depois de excluir um usuário, você não pode reverter",
|
"delete_warning": "Aviso: depois de excluir um usuário, você não pode reverter",
|
||||||
@@ -494,6 +502,7 @@
|
|||||||
"description": "Descrição",
|
"description": "Descrição",
|
||||||
"edit": "Editar usuário",
|
"edit": "Editar usuário",
|
||||||
"email_address": "Endereço de e-mail",
|
"email_address": "Endereço de e-mail",
|
||||||
|
"error_fetching_users": "Erro ao buscar usuários: {{error}}",
|
||||||
"force_password_change": "Forçar mudança de senha no login",
|
"force_password_change": "Forçar mudança de senha no login",
|
||||||
"id": "ID do usuário.",
|
"id": "ID do usuário.",
|
||||||
"last_login": "Último login",
|
"last_login": "Último login",
|
||||||
@@ -509,7 +518,7 @@
|
|||||||
"provide_password": "Forneça uma senha válida",
|
"provide_password": "Forneça uma senha válida",
|
||||||
"save_avatar": "Salvar Avatar",
|
"save_avatar": "Salvar Avatar",
|
||||||
"show_hide_password": "Mostrar / ocultar senha",
|
"show_hide_password": "Mostrar / ocultar senha",
|
||||||
"update_failure": "Certifique-se de que todos os seus dados são válidos. Se você estiver modificando a senha, certifique-se de que não seja uma senha antiga.",
|
"update_failure": "Erro ao tentar atualizar: {{error}}",
|
||||||
"update_failure_title": "Atualização falhou",
|
"update_failure_title": "Atualização falhou",
|
||||||
"update_success": "Usuário atualizado com sucesso",
|
"update_success": "Usuário atualizado com sucesso",
|
||||||
"update_success_title": "Sucesso",
|
"update_success_title": "Sucesso",
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ import {
|
|||||||
CFormGroup,
|
CFormGroup,
|
||||||
CInputRadio,
|
CInputRadio,
|
||||||
CLabel,
|
CLabel,
|
||||||
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilX } from '@coreui/icons';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import DatePicker from 'react-widgets/DatePicker';
|
import DatePicker from 'react-widgets/DatePicker';
|
||||||
@@ -88,8 +91,15 @@ const BlinkModal = ({ show, toggleModal }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal show={show} onClose={toggleModal}>
|
<CModal show={show} onClose={toggleModal}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle>{t('blink.device_leds')}</CModalTitle>
|
<CModalTitle className="pl-1 pt-1">{t('blink.device_leds')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggleModal}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
{result === 'success' ? (
|
{result === 'success' ? (
|
||||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||||
|
|||||||
@@ -1,27 +1,24 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import { CButton, CModal, CModalHeader, CModalBody, CModalTitle, CPopover } from '@coreui/react';
|
||||||
CButton,
|
import CIcon from '@coreui/icons-react';
|
||||||
CModal,
|
import { cilX } from '@coreui/icons';
|
||||||
CModalHeader,
|
|
||||||
CModalBody,
|
|
||||||
CModalTitle,
|
|
||||||
CModalFooter,
|
|
||||||
} from '@coreui/react';
|
|
||||||
|
|
||||||
const DetailsModal = ({ t, show, toggle, details, commandUuid }) => (
|
const DetailsModal = ({ t, show, toggle, details, commandUuid }) => (
|
||||||
<CModal size="lg" show={show} onClose={toggle}>
|
<CModal size="lg" show={show} onClose={toggle}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle className="text-dark">{commandUuid}</CModalTitle>
|
<CModalTitle className="text-dark">{commandUuid}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggle}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
<CModalBody>
|
<CModalBody>
|
||||||
<pre className="ignore">{JSON.stringify(details, null, 4)}</pre>
|
<pre className="ignore">{JSON.stringify(details, null, 4)}</pre>
|
||||||
</CModalBody>
|
</CModalBody>
|
||||||
<CModalFooter>
|
|
||||||
<CButton color="secondary" onClick={toggle}>
|
|
||||||
{t('common.close')}
|
|
||||||
</CButton>
|
|
||||||
</CModalFooter>
|
|
||||||
</CModal>
|
</CModal>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import {
|
|||||||
CWidgetDropdown,
|
CWidgetDropdown,
|
||||||
CRow,
|
CRow,
|
||||||
CCol,
|
CCol,
|
||||||
CCollapse,
|
|
||||||
CButton,
|
CButton,
|
||||||
CDataTable,
|
CDataTable,
|
||||||
CCard,
|
CCard,
|
||||||
CPopover,
|
CPopover,
|
||||||
|
CButtonToolbar,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
import DatePicker from 'react-widgets/DatePicker';
|
import DatePicker from 'react-widgets/DatePicker';
|
||||||
@@ -21,7 +21,6 @@ import ConfirmModal from 'components/ConfirmModal';
|
|||||||
import { LoadingButton, useAuth, useDevice } from 'ucentral-libs';
|
import { LoadingButton, useAuth, useDevice } from 'ucentral-libs';
|
||||||
import WifiScanResultModalWidget from 'components/WifiScanResultModal';
|
import WifiScanResultModalWidget from 'components/WifiScanResultModal';
|
||||||
import DetailsModal from './DetailsModal';
|
import DetailsModal from './DetailsModal';
|
||||||
import styles from './index.module.scss';
|
|
||||||
|
|
||||||
const DeviceCommands = () => {
|
const DeviceCommands = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -38,8 +37,6 @@ const DeviceCommands = () => {
|
|||||||
const [showDetailsModal, setShowDetailsModal] = useState(false);
|
const [showDetailsModal, setShowDetailsModal] = useState(false);
|
||||||
const [detailsUuid, setDetailsUuid] = useState('');
|
const [detailsUuid, setDetailsUuid] = useState('');
|
||||||
const [modalDetails, setModalDetails] = useState({});
|
const [modalDetails, setModalDetails] = useState({});
|
||||||
// Main collapsible
|
|
||||||
const [collapse, setCollapse] = useState(false);
|
|
||||||
// General states
|
// General states
|
||||||
const [commands, setCommands] = useState([]);
|
const [commands, setCommands] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -50,11 +47,6 @@ const DeviceCommands = () => {
|
|||||||
const [loadingMore, setLoadingMore] = useState(false);
|
const [loadingMore, setLoadingMore] = useState(false);
|
||||||
const [showLoadingMore, setShowLoadingMore] = useState(true);
|
const [showLoadingMore, setShowLoadingMore] = useState(true);
|
||||||
|
|
||||||
const toggle = (e) => {
|
|
||||||
setCollapse(!collapse);
|
|
||||||
e.preventDefault();
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleScanModal = () => {
|
const toggleScanModal = () => {
|
||||||
setShowScanModal(!showScanModal);
|
setShowScanModal(!showScanModal);
|
||||||
};
|
};
|
||||||
@@ -196,17 +188,15 @@ const DeviceCommands = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ key: 'UUID', label: t('common.id'), _style: { width: '28%' } },
|
{ key: 'command', label: t('common.command'), _style: { width: '15%' } },
|
||||||
{ key: 'command', label: t('common.command'), _style: { width: '10%' } },
|
{ key: 'completed', label: t('common.completed'), filter: false, _style: { width: '20%' } },
|
||||||
{ key: 'completed', label: t('common.completed'), filter: false, _style: { width: '16%' } },
|
{ key: 'submitted', label: t('common.submitted'), filter: false, _style: { width: '20%' } },
|
||||||
{ key: 'submitted', label: t('common.submitted'), filter: false, _style: { width: '16%' } },
|
|
||||||
{ key: 'executed', label: t('common.executed'), filter: false, _style: { width: '16%' } },
|
|
||||||
{
|
{
|
||||||
key: 'show_buttons',
|
key: 'show_buttons',
|
||||||
label: '',
|
label: '',
|
||||||
sorter: false,
|
sorter: false,
|
||||||
filter: false,
|
filter: false,
|
||||||
_style: { width: '14%' },
|
_style: { width: '1%' },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -252,23 +242,13 @@ const DeviceCommands = () => {
|
|||||||
}, [commands]);
|
}, [commands]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CWidgetDropdown
|
<div>
|
||||||
inverse="true"
|
<CWidgetDropdown
|
||||||
color="gradient-primary"
|
inverse="true"
|
||||||
header={t('commands.title')}
|
color="gradient-primary"
|
||||||
footerSlot={
|
header={t('commands.title')}
|
||||||
<div className={styles.footer}>
|
footerSlot={
|
||||||
<CCollapse show={collapse}>
|
<div className="pb-1 px-3">
|
||||||
<CRow>
|
|
||||||
<CCol />
|
|
||||||
<CCol className="text-right">
|
|
||||||
<div>
|
|
||||||
<CButton onClick={refreshCommands} size="sm">
|
|
||||||
<CIcon name="cil-sync" content={cilSync} className="text-white" size="2xl" />
|
|
||||||
</CButton>
|
|
||||||
</div>
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
<CRow className="mb-2">
|
<CRow className="mb-2">
|
||||||
<CCol>
|
<CCol>
|
||||||
From:
|
From:
|
||||||
@@ -280,8 +260,9 @@ const DeviceCommands = () => {
|
|||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<CCard>
|
<CCard>
|
||||||
<div className={['overflow-auto', styles.scrollableBox].join(' ')}>
|
<div className="overflow-auto" style={{ height: '200px' }}>
|
||||||
<CDataTable
|
<CDataTable
|
||||||
|
border
|
||||||
loading={loading}
|
loading={loading}
|
||||||
items={commands ?? []}
|
items={commands ?? []}
|
||||||
fields={columns}
|
fields={columns}
|
||||||
@@ -302,98 +283,100 @@ const DeviceCommands = () => {
|
|||||||
: 'Pending'}
|
: 'Pending'}
|
||||||
</td>
|
</td>
|
||||||
),
|
),
|
||||||
executed: (item) => (
|
|
||||||
<td>
|
|
||||||
{item.executed && item.executed !== ''
|
|
||||||
? prettyDate(item.executed)
|
|
||||||
: 'Pending'}
|
|
||||||
</td>
|
|
||||||
),
|
|
||||||
show_buttons: (item, index) => (
|
show_buttons: (item, index) => (
|
||||||
<td>
|
<td>
|
||||||
<CRow>
|
<CButtonToolbar
|
||||||
<CCol>
|
role="group"
|
||||||
<CPopover
|
className="justify-content-flex-end"
|
||||||
content={
|
style={{ width: '170px' }}
|
||||||
item.command === 'trace' ? t('common.download') : t('common.result')
|
>
|
||||||
}
|
<CPopover
|
||||||
|
content={
|
||||||
|
item.command === 'trace' ? t('common.download') : t('common.result')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CButton
|
||||||
|
color="primary"
|
||||||
|
variant="outline"
|
||||||
|
shape="square"
|
||||||
|
size="sm"
|
||||||
|
className="mx-2"
|
||||||
|
onClick={() => {
|
||||||
|
toggleDetails(item);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<CButton
|
{item.command === 'trace' ? (
|
||||||
color="primary"
|
<CIcon
|
||||||
variant="outline"
|
name="cil-cloud-download"
|
||||||
shape="square"
|
content={cilCloudDownload}
|
||||||
size="sm"
|
size="lg"
|
||||||
onClick={() => {
|
/>
|
||||||
toggleDetails(item);
|
) : (
|
||||||
}}
|
<CIcon
|
||||||
>
|
name="cil-calendar-check"
|
||||||
{item.command === 'trace' ? (
|
content={cilCalendarCheck}
|
||||||
<CIcon content={cilCloudDownload} size="lg" />
|
size="lg"
|
||||||
) : (
|
/>
|
||||||
<CIcon content={cilCalendarCheck} size="lg" />
|
)}
|
||||||
)}
|
</CButton>
|
||||||
</CButton>
|
</CPopover>
|
||||||
</CPopover>
|
<CPopover content={t('common.details')}>
|
||||||
</CCol>
|
<CButton
|
||||||
<CCol>
|
color="primary"
|
||||||
<CPopover content={t('common.details')}>
|
variant="outline"
|
||||||
<CButton
|
shape="square"
|
||||||
color="primary"
|
size="sm"
|
||||||
variant="outline"
|
className="mx-2"
|
||||||
shape="square"
|
onClick={() => {
|
||||||
size="sm"
|
toggleResponse(item);
|
||||||
onClick={() => {
|
}}
|
||||||
toggleResponse(item);
|
>
|
||||||
}}
|
<CIcon name="cilList" size="lg" />
|
||||||
>
|
</CButton>
|
||||||
<CIcon name="cilList" size="lg" />
|
</CPopover>
|
||||||
</CButton>
|
<CPopover content={t('common.delete')}>
|
||||||
</CPopover>
|
<CButton
|
||||||
</CCol>
|
color="primary"
|
||||||
<CCol>
|
variant="outline"
|
||||||
<CPopover content={t('common.delete')}>
|
shape="square"
|
||||||
<CButton
|
size="sm"
|
||||||
color="primary"
|
className="mx-2"
|
||||||
variant="outline"
|
onClick={() => {
|
||||||
shape="square"
|
toggleConfirmModal(item.UUID, index);
|
||||||
size="sm"
|
}}
|
||||||
onClick={() => {
|
>
|
||||||
toggleConfirmModal(item.UUID, index);
|
<CIcon name="cilTrash" size="lg" />
|
||||||
}}
|
</CButton>
|
||||||
>
|
</CPopover>
|
||||||
<CIcon name="cilTrash" size="lg" />
|
</CButtonToolbar>
|
||||||
</CButton>
|
|
||||||
</CPopover>
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
</td>
|
</td>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<CRow className={styles.loadMoreSpacing}>
|
|
||||||
{showLoadingMore && (
|
{showLoadingMore && (
|
||||||
|
<div className="mb-3">
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
label="View More"
|
label={t('common.view_more')}
|
||||||
isLoadingLabel="Loading More..."
|
isLoadingLabel={t('common.loading_more_ellipsis')}
|
||||||
isLoading={loadingMore}
|
isLoading={loadingMore}
|
||||||
action={showMoreCommands}
|
action={showMoreCommands}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
</CRow>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CCard>
|
</CCard>
|
||||||
</CCollapse>
|
</div>
|
||||||
<CButton show={collapse ? 'true' : 'false'} color="transparent" onClick={toggle} block>
|
}
|
||||||
<CIcon
|
>
|
||||||
name={collapse ? 'cilChevronTop' : 'cilChevronBottom'}
|
<div className="text-right float-right">
|
||||||
className="text-white"
|
<CButton onClick={refreshCommands} size="sm">
|
||||||
size="lg"
|
<CIcon name="cil-sync" content={cilSync} className="text-white" size="2xl" />
|
||||||
/>
|
|
||||||
</CButton>
|
</CButton>
|
||||||
</div>
|
</div>
|
||||||
}
|
</CWidgetDropdown>
|
||||||
>
|
|
||||||
<WifiScanResultModalWidget
|
<WifiScanResultModalWidget
|
||||||
show={showScanModal}
|
show={showScanModal}
|
||||||
toggle={toggleScanModal}
|
toggle={toggleScanModal}
|
||||||
@@ -408,7 +391,7 @@ const DeviceCommands = () => {
|
|||||||
details={modalDetails}
|
details={modalDetails}
|
||||||
commandUuid={detailsUuid}
|
commandUuid={detailsUuid}
|
||||||
/>
|
/>
|
||||||
</CWidgetDropdown>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
.footer {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollableBox {
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.customIconHeight {
|
|
||||||
height: 19px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loadMoreSpacing {
|
|
||||||
margin-bottom: 1%;
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,10 @@ import {
|
|||||||
CTextarea,
|
CTextarea,
|
||||||
CInvalidFeedback,
|
CInvalidFeedback,
|
||||||
CInputFile,
|
CInputFile,
|
||||||
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilX } from '@coreui/icons';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
@@ -125,8 +128,15 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal show={show} onClose={toggleModal} size="lg">
|
<CModal show={show} onClose={toggleModal} size="lg">
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle>{t('configure.title')}</CModalTitle>
|
<CModalTitle className="pl-1 pt-1">{t('configure.title')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggleModal}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
{hadSuccess ? (
|
{hadSuccess ? (
|
||||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ import {
|
|||||||
CModalFooter,
|
CModalFooter,
|
||||||
CSpinner,
|
CSpinner,
|
||||||
CBadge,
|
CBadge,
|
||||||
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilX } from '@coreui/icons';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const ConfirmModal = ({ show, toggle, action }) => {
|
const ConfirmModal = ({ show, toggle, action }) => {
|
||||||
@@ -63,8 +66,15 @@ const ConfirmModal = ({ show, toggle, action }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal className="text-dark" show={show} onClose={toggle}>
|
<CModal className="text-dark" show={show} onClose={toggle}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle>{t('delete_command.title')}</CModalTitle>
|
<CModalTitle className="pl-1 pt-1">{t('delete_command.title')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggle}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
<CModalBody>
|
<CModalBody>
|
||||||
<h6>{t('delete_command.explanation')}</h6>
|
<h6>{t('delete_command.explanation')}</h6>
|
||||||
@@ -73,9 +83,6 @@ const ConfirmModal = ({ show, toggle, action }) => {
|
|||||||
<CButton disabled={loading} color="primary" onClick={() => doAction()}>
|
<CButton disabled={loading} color="primary" onClick={() => doAction()}>
|
||||||
{getButtonContent()}
|
{getButtonContent()}
|
||||||
</CButton>
|
</CButton>
|
||||||
<CButton color="secondary" onClick={toggle}>
|
|
||||||
{t('common.cancel')}
|
|
||||||
</CButton>
|
|
||||||
</CModalFooter>
|
</CModalFooter>
|
||||||
</CModal>
|
</CModal>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { CModal, CModalHeader, CModalBody } from '@coreui/react';
|
import { CModal, CModalHeader, CModalBody, CModalTitle, CPopover, CButton } from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilSave, cilX } from '@coreui/icons';
|
||||||
import { CreateUserForm, useFormFields, useAuth, useToast } from 'ucentral-libs';
|
import { CreateUserForm, useFormFields, useAuth, useToast } from 'ucentral-libs';
|
||||||
import axiosInstance from 'utils/axiosInstance';
|
import axiosInstance from 'utils/axiosInstance';
|
||||||
import { testRegex, validateEmail } from 'utils/helper';
|
import { testRegex, validateEmail } from 'utils/helper';
|
||||||
@@ -143,14 +145,26 @@ const CreateUserModal = ({ show, toggle, getUsers }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal show={show} onClose={toggle} size="xl">
|
<CModal show={show} onClose={toggle} size="xl">
|
||||||
<CModalHeader>{t('user.create')}</CModalHeader>
|
<CModalHeader className="p-1">
|
||||||
|
<CModalTitle className="pl-1 pt-1">{t('user.create')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('user.create')}>
|
||||||
|
<CButton color="primary" variant="outline" onClick={createUser} disabled={loading}>
|
||||||
|
<CIcon content={cilSave} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggle}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
</CModalHeader>
|
||||||
<CModalBody>
|
<CModalBody>
|
||||||
<CreateUserForm
|
<CreateUserForm
|
||||||
t={t}
|
t={t}
|
||||||
fields={formFields}
|
fields={formFields}
|
||||||
updateField={updateFieldWithId}
|
updateField={updateFieldWithId}
|
||||||
createUser={createUser}
|
|
||||||
loading={loading}
|
|
||||||
policies={policies}
|
policies={policies}
|
||||||
toggleChange={toggleChange}
|
toggleChange={toggleChange}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { CModal, CModalHeader, CModalTitle, CModalBody, CCol, CRow } from '@coreui/react';
|
import {
|
||||||
|
CModal,
|
||||||
|
CModalHeader,
|
||||||
|
CModalTitle,
|
||||||
|
CModalBody,
|
||||||
|
CCol,
|
||||||
|
CRow,
|
||||||
|
CPopover,
|
||||||
|
CButton,
|
||||||
|
} from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilX } from '@coreui/icons';
|
||||||
import DatePicker from 'react-widgets/DatePicker';
|
import DatePicker from 'react-widgets/DatePicker';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { ConfirmFooter, useAuth, useDevice } from 'ucentral-libs';
|
import { ConfirmFooter, useAuth, useDevice, useToast } from 'ucentral-libs';
|
||||||
import { dateToUnix } from 'utils/helper';
|
import { dateToUnix } from 'utils/helper';
|
||||||
import axiosInstance from 'utils/axiosInstance';
|
import axiosInstance from 'utils/axiosInstance';
|
||||||
import eventBus from 'utils/eventBus';
|
import eventBus from 'utils/eventBus';
|
||||||
@@ -11,6 +22,7 @@ import eventBus from 'utils/eventBus';
|
|||||||
const DeleteLogModal = ({ show, toggle, object }) => {
|
const DeleteLogModal = ({ show, toggle, object }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { currentToken, endpoints } = useAuth();
|
const { currentToken, endpoints } = useAuth();
|
||||||
|
const { addToast } = useToast();
|
||||||
const { deviceSerialNumber } = useDevice();
|
const { deviceSerialNumber } = useDevice();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [maxDate, setMaxDate] = useState(new Date().toString());
|
const [maxDate, setMaxDate] = useState(new Date().toString());
|
||||||
@@ -36,7 +48,14 @@ const DeleteLogModal = ({ show, toggle, object }) => {
|
|||||||
return axiosInstance
|
return axiosInstance
|
||||||
.delete(`${endpoints.owgw}/api/v1/device/${deviceSerialNumber}/${object}`, options)
|
.delete(`${endpoints.owgw}/api/v1/device/${deviceSerialNumber}/${object}`, options)
|
||||||
.then(() => {})
|
.then(() => {})
|
||||||
.catch(() => {})
|
.catch((e) => {
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: t('commands.error_delete_log', { error: e.response?.data?.ErrorDescription }),
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
if (object === 'healthchecks')
|
if (object === 'healthchecks')
|
||||||
eventBus.dispatch('deletedHealth', { message: 'Healthcheck was deleted' });
|
eventBus.dispatch('deletedHealth', { message: 'Healthcheck was deleted' });
|
||||||
@@ -54,12 +73,19 @@ const DeleteLogModal = ({ show, toggle, object }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal className="text-dark" show={show} onClose={toggle}>
|
<CModal className="text-dark" show={show} onClose={toggle}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle>
|
<CModalTitle className="pl-1 pt-1">
|
||||||
{object === 'healthchecks'
|
{object === 'healthchecks'
|
||||||
? t('delete_logs.healthchecks_title')
|
? t('delete_logs.healthchecks_title')
|
||||||
: t('delete_logs.device_logs_title')}
|
: t('delete_logs.device_logs_title')}
|
||||||
</CModalTitle>
|
</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggle}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
<CModalBody>
|
<CModalBody>
|
||||||
<h6>{t('delete_logs.explanation', { object })}</h6>
|
<h6>{t('delete_logs.explanation', { object })}</h6>
|
||||||
|
|||||||
@@ -70,7 +70,14 @@ const DeviceActions = () => {
|
|||||||
const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
|
const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
|
||||||
if (newWindow) newWindow.opener = null;
|
if (newWindow) newWindow.opener = null;
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch((e) => {
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: t('connect.error_trying_to_connect', { error: e.response?.data?.ErrorDescription }),
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setConnectLoading(false);
|
setConnectLoading(false);
|
||||||
});
|
});
|
||||||
@@ -131,7 +138,7 @@ const DeviceActions = () => {
|
|||||||
</CButton>
|
</CButton>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<CRow className="mt-3">
|
<CRow className="mt-4">
|
||||||
<CCol>
|
<CCol>
|
||||||
<CButton block color="primary" onClick={toggleUpgradeModal}>
|
<CButton block color="primary" onClick={toggleUpgradeModal}>
|
||||||
{t('actions.firmware_upgrade')}
|
{t('actions.firmware_upgrade')}
|
||||||
@@ -143,7 +150,7 @@ const DeviceActions = () => {
|
|||||||
</CButton>
|
</CButton>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<CRow className="mt-3">
|
<CRow className="mt-4">
|
||||||
<CCol>
|
<CCol>
|
||||||
<CButton block color="primary" onClick={toggleScanModal}>
|
<CButton block color="primary" onClick={toggleScanModal}>
|
||||||
{t('actions.wifi_scan')}
|
{t('actions.wifi_scan')}
|
||||||
@@ -155,7 +162,7 @@ const DeviceActions = () => {
|
|||||||
</CButton>
|
</CButton>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<CRow className="mt-3">
|
<CRow className="mt-4">
|
||||||
<CCol>
|
<CCol>
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
isLoading={connectLoading}
|
isLoading={connectLoading}
|
||||||
@@ -170,7 +177,7 @@ const DeviceActions = () => {
|
|||||||
</CButton>
|
</CButton>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<CRow className="mt-3">
|
<CRow className="mt-4">
|
||||||
<CCol>
|
<CCol>
|
||||||
<CButton block color="primary" onClick={toggleQueueModal}>
|
<CButton block color="primary" onClick={toggleQueueModal}>
|
||||||
{t('commands.event_queue')}
|
{t('commands.event_queue')}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
NotesTable,
|
NotesTable,
|
||||||
useAuth,
|
useAuth,
|
||||||
useDevice,
|
useDevice,
|
||||||
|
useToast,
|
||||||
} from 'ucentral-libs';
|
} from 'ucentral-libs';
|
||||||
import DeviceConfigurationModal from './DeviceConfigurationModal';
|
import DeviceConfigurationModal from './DeviceConfigurationModal';
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ const DeviceConfiguration = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { currentToken, endpoints } = useAuth();
|
const { currentToken, endpoints } = useAuth();
|
||||||
const { deviceSerialNumber } = useDevice();
|
const { deviceSerialNumber } = useDevice();
|
||||||
|
const { addToast } = useToast();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const [collapse, setCollapse] = useState(false);
|
const [collapse, setCollapse] = useState(false);
|
||||||
@@ -61,7 +63,14 @@ const DeviceConfiguration = () => {
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
setDevice(response.data);
|
setDevice(response.data);
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch((e) => {
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: t('device.error_fetching_device', { error: e.response?.data?.ErrorDescription }),
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveNote = (currentNote) => {
|
const saveNote = (currentNote) => {
|
||||||
@@ -153,46 +162,46 @@ const DeviceConfiguration = () => {
|
|||||||
{device.firmware}
|
{device.firmware}
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<CRow className="mt-2">
|
|
||||||
<CCol md="3">
|
|
||||||
<CLabel>{t('configuration.last_configuration_change')} : </CLabel>
|
|
||||||
</CCol>
|
|
||||||
<CCol xs="12" md="9">
|
|
||||||
{prettyDate(device.lastConfigurationChange)}
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
<CRow className="mt-2">
|
|
||||||
<CCol md="3">
|
|
||||||
<CLabel>{t('common.mac')} :</CLabel>
|
|
||||||
</CCol>
|
|
||||||
<CCol xs="12" md="9">
|
|
||||||
{device.macAddress}
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
<CRow className="mt-2 mb-4">
|
|
||||||
<CCol md="3">
|
|
||||||
<CLabel className="align-middle">{t('configuration.device_password')} : </CLabel>
|
|
||||||
</CCol>
|
|
||||||
<CCol xs="12" md="2">
|
|
||||||
{getPassword()}
|
|
||||||
</CCol>
|
|
||||||
<CCol md="7">
|
|
||||||
<HideTextButton t={t} toggle={toggleShowPassword} show={showPassword} />
|
|
||||||
<CopyToClipboardButton
|
|
||||||
t={t}
|
|
||||||
size="sm"
|
|
||||||
content={device?.devicePassword === '' ? 'openwifi' : device.devicePassword}
|
|
||||||
/>
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
<NotesTable
|
|
||||||
t={t}
|
|
||||||
notes={device.notes}
|
|
||||||
loading={loading}
|
|
||||||
addNote={saveNote}
|
|
||||||
descriptionColumn={false}
|
|
||||||
/>
|
|
||||||
<CCollapse show={collapse}>
|
<CCollapse show={collapse}>
|
||||||
|
<CRow className="mt-2">
|
||||||
|
<CCol md="3">
|
||||||
|
<CLabel>{t('configuration.last_configuration_change')} : </CLabel>
|
||||||
|
</CCol>
|
||||||
|
<CCol xs="12" md="9">
|
||||||
|
{prettyDate(device.lastConfigurationChange)}
|
||||||
|
</CCol>
|
||||||
|
</CRow>
|
||||||
|
<CRow className="mt-2">
|
||||||
|
<CCol md="3">
|
||||||
|
<CLabel>{t('common.mac')} :</CLabel>
|
||||||
|
</CCol>
|
||||||
|
<CCol xs="12" md="9">
|
||||||
|
{device.macAddress}
|
||||||
|
</CCol>
|
||||||
|
</CRow>
|
||||||
|
<CRow className="mt-2 mb-4">
|
||||||
|
<CCol md="3">
|
||||||
|
<CLabel className="align-middle">{t('configuration.device_password')} : </CLabel>
|
||||||
|
</CCol>
|
||||||
|
<CCol xs="12" md="2">
|
||||||
|
{getPassword()}
|
||||||
|
</CCol>
|
||||||
|
<CCol md="7">
|
||||||
|
<HideTextButton t={t} toggle={toggleShowPassword} show={showPassword} />
|
||||||
|
<CopyToClipboardButton
|
||||||
|
t={t}
|
||||||
|
size="sm"
|
||||||
|
content={device?.devicePassword === '' ? 'openwifi' : device.devicePassword}
|
||||||
|
/>
|
||||||
|
</CCol>
|
||||||
|
</CRow>
|
||||||
|
<NotesTable
|
||||||
|
t={t}
|
||||||
|
notes={device.notes}
|
||||||
|
loading={loading}
|
||||||
|
addNote={saveNote}
|
||||||
|
descriptionColumn={false}
|
||||||
|
/>
|
||||||
<CRow className="mt-2">
|
<CRow className="mt-2">
|
||||||
<CCol md="3">
|
<CCol md="3">
|
||||||
<CLabel>{t('configuration.last_configuration_download')} : </CLabel>
|
<CLabel>{t('configuration.last_configuration_download')} : </CLabel>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
CPopover,
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilTrash } from '@coreui/icons';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import DatePicker from 'react-widgets/DatePicker';
|
import DatePicker from 'react-widgets/DatePicker';
|
||||||
import { prettyDate, dateToUnix } from 'utils/helper';
|
import { prettyDate, dateToUnix } from 'utils/helper';
|
||||||
@@ -25,7 +26,6 @@ const DeviceHealth = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { currentToken, endpoints } = useAuth();
|
const { currentToken, endpoints } = useAuth();
|
||||||
const { deviceSerialNumber } = useDevice();
|
const { deviceSerialNumber } = useDevice();
|
||||||
const [collapse, setCollapse] = useState(false);
|
|
||||||
const [details, setDetails] = useState([]);
|
const [details, setDetails] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [healthChecks, setHealthChecks] = useState([]);
|
const [healthChecks, setHealthChecks] = useState([]);
|
||||||
@@ -42,11 +42,6 @@ const DeviceHealth = () => {
|
|||||||
setShowDeleteModal(!showDeleteModal);
|
setShowDeleteModal(!showDeleteModal);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggle = (e) => {
|
|
||||||
setCollapse(!collapse);
|
|
||||||
e.preventDefault();
|
|
||||||
};
|
|
||||||
|
|
||||||
const modifyStart = (value) => {
|
const modifyStart = (value) => {
|
||||||
setStart(value);
|
setStart(value);
|
||||||
};
|
};
|
||||||
@@ -195,96 +190,71 @@ const DeviceHealth = () => {
|
|||||||
color={barColor}
|
color={barColor}
|
||||||
inverse="true"
|
inverse="true"
|
||||||
footerSlot={
|
footerSlot={
|
||||||
<div className="p-4">
|
<div className="pb-1 px-3">
|
||||||
<CProgress className="mb-3" color="white" value={sanityLevel ?? 0} />
|
<CProgress className="mb-3" color="white" value={sanityLevel ?? 0} />
|
||||||
<CCollapse show={collapse}>
|
<CRow className="mb-3">
|
||||||
<div className="text-right">
|
<CCol>
|
||||||
<CPopover content={t('common.delete')}>
|
{t('common.from')}
|
||||||
<CButton
|
:
|
||||||
color="light"
|
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
||||||
shape="square"
|
</CCol>
|
||||||
size="sm"
|
<CCol>
|
||||||
onClick={() => {
|
{t('common.to')}
|
||||||
toggleDeleteModal();
|
:
|
||||||
}}
|
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
||||||
>
|
</CCol>
|
||||||
<CIcon name="cilTrash" size="lg" />
|
</CRow>
|
||||||
</CButton>
|
<CCard className="p-0">
|
||||||
</CPopover>
|
<div className="overflow-auto" style={{ height: '200px' }}>
|
||||||
|
<CDataTable
|
||||||
|
border
|
||||||
|
items={healthChecks ?? []}
|
||||||
|
fields={columns}
|
||||||
|
className="text-white"
|
||||||
|
loading={loading}
|
||||||
|
sorterValue={{ column: 'recorded', desc: 'true' }}
|
||||||
|
scopedSlots={{
|
||||||
|
UUID: (item) => <td className="align-middle">{item.UUID}</td>,
|
||||||
|
recorded: (item) => <td className="align-middle">{prettyDate(item.recorded)}</td>,
|
||||||
|
sanity: (item) => <td className="align-middle">{`${item.sanity}%`}</td>,
|
||||||
|
show_details: (item, index) => (
|
||||||
|
<td className="align-middle">
|
||||||
|
<CButton
|
||||||
|
color="primary"
|
||||||
|
variant={details.includes(index) ? '' : 'outline'}
|
||||||
|
shape="square"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
toggleDetails(index);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CIcon name="cilList" size="lg" />
|
||||||
|
</CButton>
|
||||||
|
</td>
|
||||||
|
),
|
||||||
|
details: (item, index) => (
|
||||||
|
<CCollapse show={details.includes(index)}>
|
||||||
|
<CCardBody>
|
||||||
|
<h5>{t('common.details')}</h5>
|
||||||
|
<div>{getDetails(index, item.values)}</div>
|
||||||
|
</CCardBody>
|
||||||
|
</CCollapse>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{showLoadingMore && (
|
||||||
|
<div className="mb-3">
|
||||||
|
<LoadingButton
|
||||||
|
label={t('common.view_more')}
|
||||||
|
isLoadingLabel={t('common.loading_more_ellipsis')}
|
||||||
|
isLoading={loadingMore}
|
||||||
|
action={showMoreLogs}
|
||||||
|
variant="outline"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<CRow className="mb-3">
|
</CCard>
|
||||||
<CCol>
|
|
||||||
{t('common.from')}
|
|
||||||
:
|
|
||||||
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
|
||||||
</CCol>
|
|
||||||
<CCol>
|
|
||||||
{t('common.to')}
|
|
||||||
:
|
|
||||||
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
<CCard className="p-0">
|
|
||||||
<div className="overflow-auto" style={{ height: '250px' }}>
|
|
||||||
<CDataTable
|
|
||||||
border
|
|
||||||
items={healthChecks ?? []}
|
|
||||||
fields={columns}
|
|
||||||
className="text-white"
|
|
||||||
loading={loading}
|
|
||||||
sorterValue={{ column: 'recorded', desc: 'true' }}
|
|
||||||
scopedSlots={{
|
|
||||||
UUID: (item) => <td className="align-middle">{item.UUID}</td>,
|
|
||||||
recorded: (item) => (
|
|
||||||
<td className="align-middle">{prettyDate(item.recorded)}</td>
|
|
||||||
),
|
|
||||||
sanity: (item) => <td className="align-middle">{`${item.sanity}%`}</td>,
|
|
||||||
show_details: (item, index) => (
|
|
||||||
<td className="align-middle">
|
|
||||||
<CButton
|
|
||||||
color="primary"
|
|
||||||
variant={details.includes(index) ? '' : 'outline'}
|
|
||||||
shape="square"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => {
|
|
||||||
toggleDetails(index);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CIcon name="cilList" size="lg" />
|
|
||||||
</CButton>
|
|
||||||
</td>
|
|
||||||
),
|
|
||||||
details: (item, index) => (
|
|
||||||
<CCollapse show={details.includes(index)}>
|
|
||||||
<CCardBody>
|
|
||||||
<h5>{t('common.details')}</h5>
|
|
||||||
<div>{getDetails(index, item.values)}</div>
|
|
||||||
</CCardBody>
|
|
||||||
</CCollapse>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{showLoadingMore && (
|
|
||||||
<div className="mb-3">
|
|
||||||
<LoadingButton
|
|
||||||
label={t('common.view_more')}
|
|
||||||
isLoadingLabel={t('common.loading_more_ellipsis')}
|
|
||||||
isLoading={loadingMore}
|
|
||||||
action={showMoreLogs}
|
|
||||||
variant="outline"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</CCard>
|
|
||||||
</CCollapse>
|
|
||||||
<CButton show={collapse ? 'true' : 'false'} color="transparent" onClick={toggle} block>
|
|
||||||
<CIcon
|
|
||||||
name={collapse ? 'cilChevronTop' : 'cilChevronBottom'}
|
|
||||||
className="text-white"
|
|
||||||
size="lg"
|
|
||||||
/>
|
|
||||||
</CButton>
|
|
||||||
<DeleteLogModal
|
<DeleteLogModal
|
||||||
serialNumber={deviceSerialNumber}
|
serialNumber={deviceSerialNumber}
|
||||||
object="healthchecks"
|
object="healthchecks"
|
||||||
@@ -293,7 +263,15 @@ const DeviceHealth = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
>
|
||||||
|
<div className="text-right float-right">
|
||||||
|
<CPopover content={t('common.delete')}>
|
||||||
|
<CButton onClick={toggleDeleteModal} size="sm">
|
||||||
|
<CIcon name="cil-trash" content={cilTrash} className="text-white" size="2xl" />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
</CWidgetDropdown>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,13 @@ const DeviceList = () => {
|
|||||||
setDevices(fullDevices);
|
setDevices(fullDevices);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: t('device.error_fetching_devices', { error: e.response?.data?.ErrorDescription }),
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -130,7 +136,13 @@ const DeviceList = () => {
|
|||||||
}
|
}
|
||||||
getDeviceInformation(selectedPage);
|
getDeviceInformation(selectedPage);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: t('device.error_fetching_devices', { error: e.response?.data?.ErrorDescription }),
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -179,7 +191,13 @@ const DeviceList = () => {
|
|||||||
setDevices(newList);
|
setDevices(newList);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: t('device.error_fetching_devices', { error: e.response?.data?.ErrorDescription }),
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -282,10 +300,10 @@ const DeviceList = () => {
|
|||||||
const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
|
const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
|
||||||
if (newWindow) newWindow.opener = null;
|
if (newWindow) newWindow.opener = null;
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
addToast({
|
addToast({
|
||||||
title: t('common.error'),
|
title: t('common.error'),
|
||||||
body: t('common.unable_to_connect'),
|
body: t('connect.error_trying_to_connect', { error: e.response?.data?.ErrorDescription }),
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
autohide: true,
|
autohide: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
CPopover,
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilTrash } from '@coreui/icons';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import DatePicker from 'react-widgets/DatePicker';
|
import DatePicker from 'react-widgets/DatePicker';
|
||||||
import { prettyDate, dateToUnix } from 'utils/helper';
|
import { prettyDate, dateToUnix } from 'utils/helper';
|
||||||
@@ -24,7 +25,6 @@ const DeviceLogs = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { currentToken, endpoints } = useAuth();
|
const { currentToken, endpoints } = useAuth();
|
||||||
const { deviceSerialNumber } = useDevice();
|
const { deviceSerialNumber } = useDevice();
|
||||||
const [collapse, setCollapse] = useState(false);
|
|
||||||
const [details, setDetails] = useState([]);
|
const [details, setDetails] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [logs, setLogs] = useState([]);
|
const [logs, setLogs] = useState([]);
|
||||||
@@ -39,11 +39,6 @@ const DeviceLogs = () => {
|
|||||||
setShowDeleteModal(!showDeleteModal);
|
setShowDeleteModal(!showDeleteModal);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggle = (e) => {
|
|
||||||
setCollapse(!collapse);
|
|
||||||
e.preventDefault();
|
|
||||||
};
|
|
||||||
|
|
||||||
const modifyStart = (value) => {
|
const modifyStart = (value) => {
|
||||||
setStart(value);
|
setStart(value);
|
||||||
};
|
};
|
||||||
@@ -176,91 +171,76 @@ const DeviceLogs = () => {
|
|||||||
color="gradient-info"
|
color="gradient-info"
|
||||||
header={t('device_logs.title')}
|
header={t('device_logs.title')}
|
||||||
footerSlot={
|
footerSlot={
|
||||||
<div className="p-4">
|
<div className="pb-1 px-3">
|
||||||
<CCollapse show={collapse}>
|
<CRow className="mb-3">
|
||||||
<div className="text-right">
|
<CCol>
|
||||||
<CPopover content={t('common.delete')}>
|
{t('common.from')}
|
||||||
<CButton
|
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
||||||
color="light"
|
</CCol>
|
||||||
shape="square"
|
<CCol>
|
||||||
size="sm"
|
{t('common.to')}
|
||||||
onClick={() => {
|
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
||||||
toggleDeleteModal();
|
</CCol>
|
||||||
}}
|
</CRow>
|
||||||
>
|
<CCard>
|
||||||
<CIcon name="cilTrash" size="lg" />
|
<div className="overflow-auto" style={{ height: '250px' }}>
|
||||||
</CButton>
|
<CDataTable
|
||||||
</CPopover>
|
items={logs ?? []}
|
||||||
|
fields={columns}
|
||||||
|
loading={loading}
|
||||||
|
className="text-white"
|
||||||
|
sorterValue={{ column: 'recorded', desc: 'true' }}
|
||||||
|
scopedSlots={{
|
||||||
|
recorded: (item) => <td>{prettyDate(item.recorded)}</td>,
|
||||||
|
show_details: (item, index) => (
|
||||||
|
<td className="py-2">
|
||||||
|
<CButton
|
||||||
|
color="primary"
|
||||||
|
variant={details.includes(index) ? '' : 'outline'}
|
||||||
|
shape="square"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
toggleDetails(index);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CIcon name="cilList" size="lg" />
|
||||||
|
</CButton>
|
||||||
|
</td>
|
||||||
|
),
|
||||||
|
details: (item, index) => (
|
||||||
|
<CCollapse show={details.includes(index)}>
|
||||||
|
<CCardBody>
|
||||||
|
<h5>{t('common.details')}</h5>
|
||||||
|
<div>{getDetails(index, item)}</div>
|
||||||
|
</CCardBody>
|
||||||
|
</CCollapse>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{showLoadingMore && (
|
||||||
|
<div className="mb-3">
|
||||||
|
<LoadingButton
|
||||||
|
label={t('common.view_more')}
|
||||||
|
isLoadingLabel={t('common.loading_more_ellipsis')}
|
||||||
|
isLoading={loadingMore}
|
||||||
|
action={showMoreLogs}
|
||||||
|
variant="outline"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<CRow className="mb-3">
|
</CCard>
|
||||||
<CCol>
|
|
||||||
{t('common.from')}
|
|
||||||
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
|
||||||
</CCol>
|
|
||||||
<CCol>
|
|
||||||
{t('common.to')}
|
|
||||||
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
<CCard>
|
|
||||||
<div className="overflow-auto" style={{ height: '250px' }}>
|
|
||||||
<CDataTable
|
|
||||||
items={logs ?? []}
|
|
||||||
fields={columns}
|
|
||||||
loading={loading}
|
|
||||||
className="text-white"
|
|
||||||
sorterValue={{ column: 'recorded', desc: 'true' }}
|
|
||||||
scopedSlots={{
|
|
||||||
recorded: (item) => <td>{prettyDate(item.recorded)}</td>,
|
|
||||||
show_details: (item, index) => (
|
|
||||||
<td className="py-2">
|
|
||||||
<CButton
|
|
||||||
color="primary"
|
|
||||||
variant={details.includes(index) ? '' : 'outline'}
|
|
||||||
shape="square"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => {
|
|
||||||
toggleDetails(index);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CIcon name="cilList" size="lg" />
|
|
||||||
</CButton>
|
|
||||||
</td>
|
|
||||||
),
|
|
||||||
details: (item, index) => (
|
|
||||||
<CCollapse show={details.includes(index)}>
|
|
||||||
<CCardBody>
|
|
||||||
<h5>{t('common.details')}</h5>
|
|
||||||
<div>{getDetails(index, item)}</div>
|
|
||||||
</CCardBody>
|
|
||||||
</CCollapse>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{showLoadingMore && (
|
|
||||||
<div className="mb-3">
|
|
||||||
<LoadingButton
|
|
||||||
label={t('common.view_more')}
|
|
||||||
isLoadingLabel={t('common.loading_more_ellipsis')}
|
|
||||||
isLoading={loadingMore}
|
|
||||||
action={showMoreLogs}
|
|
||||||
variant="outline"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</CCard>
|
|
||||||
</CCollapse>
|
|
||||||
<CButton show={collapse ? 'true' : 'false'} color="transparent" onClick={toggle} block>
|
|
||||||
<CIcon
|
|
||||||
name={collapse ? 'cilChevronTop' : 'cilChevronBottom'}
|
|
||||||
className="text-white"
|
|
||||||
size="lg"
|
|
||||||
/>
|
|
||||||
</CButton>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
>
|
||||||
|
<div className="text-right float-right">
|
||||||
|
<CPopover content={t('common.delete')}>
|
||||||
|
<CButton onClick={toggleDeleteModal} size="sm">
|
||||||
|
<CIcon name="cil-trash" content={cilTrash} className="text-white" size="2xl" />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
</CWidgetDropdown>
|
||||||
<DeleteLogModal
|
<DeleteLogModal
|
||||||
serialNumber={deviceSerialNumber}
|
serialNumber={deviceSerialNumber}
|
||||||
object="logs"
|
object="logs"
|
||||||
|
|||||||
@@ -1,17 +1,42 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import axiosInstance from 'utils/axiosInstance';
|
import axiosInstance from 'utils/axiosInstance';
|
||||||
import { DeviceStatusCard as Card, useDevice, useAuth } from 'ucentral-libs';
|
import { DeviceStatusCard as Card, useDevice, useAuth, useToast } from 'ucentral-libs';
|
||||||
|
|
||||||
const DeviceStatusCard = () => {
|
const DeviceStatusCard = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { currentToken, endpoints } = useAuth();
|
const { currentToken, endpoints } = useAuth();
|
||||||
const { deviceSerialNumber } = useDevice();
|
const { deviceSerialNumber } = useDevice();
|
||||||
|
const { addToast } = useToast();
|
||||||
const [lastStats, setLastStats] = useState(null);
|
const [lastStats, setLastStats] = useState(null);
|
||||||
const [status, setStatus] = useState(null);
|
const [status, setStatus] = useState(null);
|
||||||
|
const [deviceConfig, setDeviceConfig] = useState(null);
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const getDevice = () => {
|
||||||
|
const options = {
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: `Bearer ${currentToken}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
axiosInstance
|
||||||
|
.get(`${endpoints.owgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}`, options)
|
||||||
|
.then((response) => {
|
||||||
|
setDeviceConfig(response.data);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: t('device.error_fetching_device', { error: e.response?.data?.ErrorDescription }),
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const options = {
|
const options = {
|
||||||
@@ -45,9 +70,17 @@ const DeviceStatusCard = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const refresh = () => {
|
||||||
|
getData();
|
||||||
|
getDevice();
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setError(false);
|
setError(false);
|
||||||
if (deviceSerialNumber) getData();
|
if (deviceSerialNumber) {
|
||||||
|
getDevice();
|
||||||
|
getData();
|
||||||
|
}
|
||||||
}, [deviceSerialNumber]);
|
}, [deviceSerialNumber]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -56,7 +89,8 @@ const DeviceStatusCard = () => {
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
error={error}
|
error={error}
|
||||||
deviceSerialNumber={deviceSerialNumber}
|
deviceSerialNumber={deviceSerialNumber}
|
||||||
getData={getData}
|
getData={refresh}
|
||||||
|
deviceConfig={deviceConfig}
|
||||||
status={status}
|
status={status}
|
||||||
lastStats={lastStats}
|
lastStats={lastStats}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -145,10 +145,10 @@ const EditUserModal = ({ show, toggle, userId, getUsers }) => {
|
|||||||
getUsers();
|
getUsers();
|
||||||
toggle();
|
toggle();
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
addToast({
|
addToast({
|
||||||
title: t('user.update_failure_title'),
|
title: t('user.update_failure_title'),
|
||||||
body: t('user.update_failure'),
|
body: t('user.update_failure', { error: e.response?.data?.ErrorDescription }),
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
autohide: true,
|
autohide: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ const EventQueueModal = ({ show, toggle }) => {
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
setResult(response.data);
|
setResult(response.data);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
addToast({
|
addToast({
|
||||||
title: t('common.error'),
|
title: t('common.error'),
|
||||||
body: t('commands.unable_queue'),
|
body: t('commands.unable_queue', { error: e.response?.data?.ErrorDescription }),
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
autohide: true,
|
autohide: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ import {
|
|||||||
CForm,
|
CForm,
|
||||||
CSwitch,
|
CSwitch,
|
||||||
CAlert,
|
CAlert,
|
||||||
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilX } from '@coreui/icons';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
@@ -84,8 +87,15 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal show={show} onClose={toggleModal}>
|
<CModal show={show} onClose={toggleModal}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle>{t('factory_reset.title')}</CModalTitle>
|
<CModalTitle className="pl-1 pt-1">{t('factory_reset.title')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggleModal}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
{hadSuccess ? (
|
{hadSuccess ? (
|
||||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const FirmwareHistoryModal = ({ serialNumber, show, toggle }) => {
|
|||||||
return (
|
return (
|
||||||
<CModal size="xl" show={show} onClose={toggle} scrollable>
|
<CModal size="xl" show={show} onClose={toggle} scrollable>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader closeButton>
|
||||||
<CModalTitle>
|
<CModalTitle className="pl-1 pt-1">
|
||||||
#{serialNumber} {t('firmware.history_title')}
|
#{serialNumber} {t('firmware.history_title')}
|
||||||
</CModalTitle>
|
</CModalTitle>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { CButton, CSpinner, CModalFooter } from '@coreui/react';
|
|
||||||
|
|
||||||
const UpgradeFooter = ({
|
|
||||||
isNow,
|
|
||||||
isShown,
|
|
||||||
isLoading,
|
|
||||||
action,
|
|
||||||
color,
|
|
||||||
variant,
|
|
||||||
block,
|
|
||||||
toggleParent,
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [askingIfSure, setAskingIfSure] = useState(false);
|
|
||||||
|
|
||||||
const confirmingIfSure = () => {
|
|
||||||
setAskingIfSure(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setAskingIfSure(false);
|
|
||||||
}, [isShown]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CModalFooter>
|
|
||||||
<div hidden={!askingIfSure}>{t('common.are_you_sure')}</div>
|
|
||||||
<CButton
|
|
||||||
disabled={isLoading}
|
|
||||||
hidden={askingIfSure}
|
|
||||||
color={color}
|
|
||||||
variant={variant}
|
|
||||||
onClick={() => confirmingIfSure()}
|
|
||||||
block={block}
|
|
||||||
>
|
|
||||||
{isNow ? t('upgrade.upgrade') : t('common.schedule')}
|
|
||||||
</CButton>
|
|
||||||
<CButton
|
|
||||||
disabled={isLoading}
|
|
||||||
hidden={!askingIfSure}
|
|
||||||
color={color}
|
|
||||||
onClick={() => action()}
|
|
||||||
block={block}
|
|
||||||
>
|
|
||||||
{isLoading ? t('common.loading_ellipsis') : t('common.yes')}
|
|
||||||
<CSpinner color="light" hidden={!isLoading} component="span" size="sm" />
|
|
||||||
</CButton>
|
|
||||||
<CButton color="secondary" onClick={toggleParent}>
|
|
||||||
{t('common.cancel')}
|
|
||||||
</CButton>
|
|
||||||
</CModalFooter>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
UpgradeFooter.propTypes = {
|
|
||||||
isNow: PropTypes.bool.isRequired,
|
|
||||||
isLoading: PropTypes.bool.isRequired,
|
|
||||||
block: PropTypes.bool,
|
|
||||||
action: PropTypes.func.isRequired,
|
|
||||||
color: PropTypes.string,
|
|
||||||
variant: PropTypes.string,
|
|
||||||
toggleParent: PropTypes.func.isRequired,
|
|
||||||
isShown: PropTypes.bool.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
UpgradeFooter.defaultProps = {
|
|
||||||
color: 'primary',
|
|
||||||
variant: '',
|
|
||||||
block: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UpgradeFooter;
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { CModalBody } from '@coreui/react';
|
|
||||||
import { v4 as createUuid } from 'uuid';
|
|
||||||
import { useAuth } from 'ucentral-libs';
|
|
||||||
import axiosInstance from 'utils/axiosInstance';
|
|
||||||
|
|
||||||
const UpgradeWaitingBody = ({ serialNumber }) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { currentToken, endpoints } = useAuth();
|
|
||||||
const [currentStep, setCurrentStep] = useState(0);
|
|
||||||
const [secondsElapsed, setSecondsElapsed] = useState(0);
|
|
||||||
const [labelsToShow, setLabelsToShow] = useState(['upgrade.command_submitted']);
|
|
||||||
|
|
||||||
const getDeviceConnection = () => {
|
|
||||||
const options = {
|
|
||||||
headers: {
|
|
||||||
Accept: 'application/json',
|
|
||||||
Authorization: `Bearer ${currentToken}`,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
axiosInstance
|
|
||||||
.get(`${endpoints.owgw}/api/v1/device/${encodeURIComponent(serialNumber)}/status`, options)
|
|
||||||
.then((response) => response.data.connected)
|
|
||||||
.catch(() => {});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getFirmwareVersion = () => {
|
|
||||||
const options = {
|
|
||||||
headers: {
|
|
||||||
Accept: 'application/json',
|
|
||||||
Authorization: `Bearer ${currentToken}`,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
axiosInstance
|
|
||||||
.get(`${endpoints.owgw}/api/v1/device/${encodeURIComponent(serialNumber)}`, options)
|
|
||||||
.then((response) => response.data.firmware)
|
|
||||||
.catch(() => {});
|
|
||||||
};
|
|
||||||
|
|
||||||
const refreshStep = () => {
|
|
||||||
if (currentStep === 0 && !getDeviceConnection) {
|
|
||||||
const labelsToAdd = [
|
|
||||||
t('upgrade.device_disconnected'),
|
|
||||||
t('upgrade.device_upgrading_firmware'),
|
|
||||||
t('upgrade.waiting_for_device'),
|
|
||||||
];
|
|
||||||
setLabelsToShow([...labelsToShow, ...labelsToAdd]);
|
|
||||||
setCurrentStep(1);
|
|
||||||
} else if (currentStep === 1 && getDeviceConnection()) {
|
|
||||||
const newFirmware = `: ${getFirmwareVersion()}`;
|
|
||||||
const labelsToAdd = [
|
|
||||||
t('upgrade.device_reconnected'),
|
|
||||||
`${t('upgrade.new_version')}: ${newFirmware}`,
|
|
||||||
];
|
|
||||||
setLabelsToShow([...labelsToShow, ...labelsToAdd]);
|
|
||||||
setCurrentStep(2);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const refreshIntervalId = setInterval(() => {
|
|
||||||
refreshStep();
|
|
||||||
}, 5000);
|
|
||||||
|
|
||||||
const timerIntervalId = setInterval(() => {
|
|
||||||
setSecondsElapsed(secondsElapsed + 1);
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearInterval(refreshIntervalId);
|
|
||||||
clearInterval(timerIntervalId);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CModalBody>
|
|
||||||
<div className="consoleBox">
|
|
||||||
{labelsToShow.map((label) => (
|
|
||||||
<p key={createUuid()}>
|
|
||||||
{new Date().toString()}:{label}
|
|
||||||
</p>
|
|
||||||
))}
|
|
||||||
<p>
|
|
||||||
{t('common.seconds_elapsed')}:{secondsElapsed}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</CModalBody>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
UpgradeWaitingBody.propTypes = {
|
|
||||||
serialNumber: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UpgradeWaitingBody;
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
import {
|
|
||||||
CButton,
|
|
||||||
CModal,
|
|
||||||
CModalHeader,
|
|
||||||
CModalTitle,
|
|
||||||
CModalBody,
|
|
||||||
CSwitch,
|
|
||||||
CCol,
|
|
||||||
CRow,
|
|
||||||
CInput,
|
|
||||||
CInvalidFeedback,
|
|
||||||
CModalFooter,
|
|
||||||
} from '@coreui/react';
|
|
||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import DatePicker from 'react-widgets/DatePicker';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { dateToUnix } from 'utils/helper';
|
|
||||||
import 'react-widgets/styles.css';
|
|
||||||
import { useDevice, useAuth } from 'ucentral-libs';
|
|
||||||
import axiosInstance from 'utils/axiosInstance';
|
|
||||||
import eventBus from 'utils/eventBus';
|
|
||||||
import ButtonFooter from './UpgradeFooter';
|
|
||||||
import UpgradeWaitingBody from './UpgradeWaitingBody';
|
|
||||||
|
|
||||||
const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { currentToken, endpoints } = useAuth();
|
|
||||||
const { deviceSerialNumber, getDeviceConnection } = useDevice();
|
|
||||||
const [isNow, setIsNow] = useState(true);
|
|
||||||
const [waitForUpgrade, setWaitForUpgrade] = useState(false);
|
|
||||||
const [date, setDate] = useState(new Date().toString());
|
|
||||||
const [firmware, setFirmware] = useState('');
|
|
||||||
const [validFirmware, setValidFirmware] = useState(true);
|
|
||||||
const [validDate, setValidDate] = useState(true);
|
|
||||||
const [blockFields, setBlockFields] = useState(false);
|
|
||||||
const [disabledWaiting, setDisableWaiting] = useState(false);
|
|
||||||
const [waitingForUpgrade, setWaitingForUpgrade] = useState(false);
|
|
||||||
const [showWaitingConsole, setShowWaitingConsole] = useState(false);
|
|
||||||
const [deviceConnected, setDeviceConnected] = useState(true);
|
|
||||||
|
|
||||||
const toggleNow = () => {
|
|
||||||
if (isNow) {
|
|
||||||
setWaitForUpgrade(false);
|
|
||||||
setDisableWaiting(true);
|
|
||||||
} else {
|
|
||||||
setDisableWaiting(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsNow(!isNow);
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleWaitForUpgrade = () => {
|
|
||||||
setWaitForUpgrade(waitForUpgrade);
|
|
||||||
};
|
|
||||||
|
|
||||||
const formValidation = () => {
|
|
||||||
let valid = true;
|
|
||||||
if (firmware.trim() === '') {
|
|
||||||
setValidFirmware(false);
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNow && date.trim() === '') {
|
|
||||||
setValidDate(false);
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
return valid;
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setBlockFields(false);
|
|
||||||
setShowWaitingConsole(false);
|
|
||||||
}, [show]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setValidFirmware(true);
|
|
||||||
setValidDate(true);
|
|
||||||
}, [firmware, date]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (deviceSerialNumber !== null && show) {
|
|
||||||
const asyncGet = async () => {
|
|
||||||
const isConnected = await getDeviceConnection(
|
|
||||||
deviceSerialNumber,
|
|
||||||
currentToken,
|
|
||||||
endpoints.owgw,
|
|
||||||
);
|
|
||||||
setDisableWaiting(!isConnected);
|
|
||||||
setDeviceConnected(isConnected);
|
|
||||||
};
|
|
||||||
asyncGet();
|
|
||||||
}
|
|
||||||
}, [show]);
|
|
||||||
|
|
||||||
const postUpgrade = () => {
|
|
||||||
if (formValidation()) {
|
|
||||||
setWaitingForUpgrade(true);
|
|
||||||
setBlockFields(true);
|
|
||||||
const headers = {
|
|
||||||
Accept: 'application/json',
|
|
||||||
Authorization: `Bearer ${currentToken}`,
|
|
||||||
serialNumber: deviceSerialNumber,
|
|
||||||
};
|
|
||||||
|
|
||||||
const parameters = {
|
|
||||||
serialNumber: deviceSerialNumber,
|
|
||||||
when: isNow ? 0 : dateToUnix(date),
|
|
||||||
uri: firmware,
|
|
||||||
};
|
|
||||||
axiosInstance
|
|
||||||
.post(
|
|
||||||
`${endpoints.owgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/upgrade`,
|
|
||||||
parameters,
|
|
||||||
{ headers },
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
if (waitForUpgrade) {
|
|
||||||
setShowWaitingConsole(true);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {})
|
|
||||||
.finally(() => {
|
|
||||||
setBlockFields(false);
|
|
||||||
setWaitingForUpgrade(false);
|
|
||||||
eventBus.dispatch('actionCompleted', { message: 'An action has been completed' });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (showWaitingConsole) {
|
|
||||||
return (
|
|
||||||
<CModal show={show} onClose={toggleModal}>
|
|
||||||
<CModalHeader closeButton>
|
|
||||||
<CModalTitle>{t('upgrade.title')}</CModalTitle>
|
|
||||||
</CModalHeader>
|
|
||||||
<CModalBody>
|
|
||||||
<UpgradeWaitingBody serialNumber={deviceSerialNumber} />
|
|
||||||
</CModalBody>
|
|
||||||
<CModalFooter>
|
|
||||||
<CButton color="secondary" onClick={toggleModal}>
|
|
||||||
{t('common.close')}
|
|
||||||
</CButton>
|
|
||||||
</CModalFooter>
|
|
||||||
</CModal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CModal show={show} onClose={toggleModal}>
|
|
||||||
<CModalHeader closeButton>
|
|
||||||
<CModalTitle>{t('upgrade.title')}</CModalTitle>
|
|
||||||
</CModalHeader>
|
|
||||||
<CModalBody>
|
|
||||||
<h6>{t('upgrade.directions')}</h6>
|
|
||||||
<CRow className="mt-3">
|
|
||||||
<CCol md="4" className="mt-2">
|
|
||||||
<p>{t('upgrade.firmware_uri')}</p>
|
|
||||||
</CCol>
|
|
||||||
<CCol md="8">
|
|
||||||
<CInput
|
|
||||||
disabled={blockFields}
|
|
||||||
className={`form-control ${!validFirmware ? 'is-invalid' : ''}`}
|
|
||||||
type="text"
|
|
||||||
id="uri"
|
|
||||||
name="uri-input"
|
|
||||||
autoComplete="firmware-uri"
|
|
||||||
onChange={(event) => setFirmware(event.target.value)}
|
|
||||||
value={firmware}
|
|
||||||
/>
|
|
||||||
<CInvalidFeedback>{t('upgrade.need_uri')}</CInvalidFeedback>
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
<CRow className="mt-3">
|
|
||||||
<CCol md="8">
|
|
||||||
<p>{t('common.execute_now')}</p>
|
|
||||||
</CCol>
|
|
||||||
<CCol>
|
|
||||||
<CSwitch
|
|
||||||
disabled={blockFields}
|
|
||||||
color="primary"
|
|
||||||
defaultChecked={isNow}
|
|
||||||
onClick={toggleNow}
|
|
||||||
labelOn={t('common.yes')}
|
|
||||||
labelOff={t('common.no')}
|
|
||||||
/>
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
<CRow className="mt-3" hidden={isNow}>
|
|
||||||
<CCol md="4" className="mt-2">
|
|
||||||
<p>{t('upgrade.time')}</p>
|
|
||||||
</CCol>
|
|
||||||
<CCol xs="12" md="8">
|
|
||||||
<DatePicker
|
|
||||||
selected={new Date(date)}
|
|
||||||
value={new Date(date)}
|
|
||||||
className={`form-control ${!validDate ? 'is-invalid' : ''}`}
|
|
||||||
includeTime
|
|
||||||
disabled={blockFields}
|
|
||||||
onChange={(newDate) => setDate(newDate.toString())}
|
|
||||||
/>
|
|
||||||
<CInvalidFeedback>{t('common.need_date')}</CInvalidFeedback>
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
<CRow className="mt-3" hidden={true || !isNow || disabledWaiting || !deviceConnected}>
|
|
||||||
<CCol md="8">
|
|
||||||
<p>
|
|
||||||
{t('upgrade.wait_for_upgrade')}
|
|
||||||
<b hidden={!disabledWaiting}> {t('upgrade.offline_device')}</b>
|
|
||||||
</p>
|
|
||||||
</CCol>
|
|
||||||
<CCol>
|
|
||||||
<CSwitch
|
|
||||||
disabled={blockFields || disabledWaiting}
|
|
||||||
color="primary"
|
|
||||||
defaultChecked={waitForUpgrade}
|
|
||||||
onClick={toggleWaitForUpgrade}
|
|
||||||
labelOn={t('common.yes')}
|
|
||||||
labelOff={t('common.no')}
|
|
||||||
/>
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
</CModalBody>
|
|
||||||
<ButtonFooter
|
|
||||||
isNow={isNow}
|
|
||||||
isShown={show}
|
|
||||||
isLoading={waitingForUpgrade}
|
|
||||||
action={postUpgrade}
|
|
||||||
color="primary"
|
|
||||||
toggleParent={toggleModal}
|
|
||||||
/>
|
|
||||||
</CModal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
FirmwareUpgradeModal.propTypes = {
|
|
||||||
show: PropTypes.bool.isRequired,
|
|
||||||
toggleModal: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FirmwareUpgradeModal;
|
|
||||||
@@ -1,12 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import {
|
import { CButton, CModal, CModalHeader, CModalBody, CModalTitle, CPopover } from '@coreui/react';
|
||||||
CButton,
|
import CIcon from '@coreui/icons-react';
|
||||||
CModal,
|
import { cilX } from '@coreui/icons';
|
||||||
CModalHeader,
|
|
||||||
CModalBody,
|
|
||||||
CModalTitle,
|
|
||||||
CModalFooter,
|
|
||||||
} from '@coreui/react';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import axiosInstance from 'utils/axiosInstance';
|
import axiosInstance from 'utils/axiosInstance';
|
||||||
@@ -45,17 +40,19 @@ const LatestStatisticsModal = ({ show, toggle }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal size="lg" show={show} onClose={toggle}>
|
<CModal size="lg" show={show} onClose={toggle}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle className="text-dark">{t('statistics.latest_statistics')}</CModalTitle>
|
<CModalTitle className="text-dark">{t('statistics.latest_statistics')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggle}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
<CModalBody>
|
<CModalBody>
|
||||||
<pre className="ignore">{JSON.stringify(latestStats, null, 4)}</pre>
|
<pre className="ignore">{JSON.stringify(latestStats, null, 4)}</pre>
|
||||||
</CModalBody>
|
</CModalBody>
|
||||||
<CModalFooter>
|
|
||||||
<CButton color="secondary" onClick={toggle}>
|
|
||||||
{t('common.close')}
|
|
||||||
</CButton>
|
|
||||||
</CModalFooter>
|
|
||||||
</CModal>
|
</CModal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { CCard, CCardHeader, CCardBody, CRow, CCol, CPopover, CButton } from '@coreui/react';
|
import { CCard, CCardHeader, CCardBody, CPopover, CButton } from '@coreui/react';
|
||||||
import { cilSync } from '@coreui/icons';
|
import { cilSync } from '@coreui/icons';
|
||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
import eventBus from 'utils/eventBus';
|
import eventBus from 'utils/eventBus';
|
||||||
@@ -36,38 +36,31 @@ const DeviceStatisticsCard = () => {
|
|||||||
<div>
|
<div>
|
||||||
<CCard>
|
<CCard>
|
||||||
<CCardHeader>
|
<CCardHeader>
|
||||||
<CRow>
|
<div className="d-flex flex-row-reverse align-items-center">
|
||||||
<CCol>
|
<div className="pl-2">
|
||||||
<div className="text-value-xxl pt-2">{t('statistics.title')}</div>
|
<CPopover content={t('common.refresh')}>
|
||||||
</CCol>
|
<CButton color="primary" variant="outline" onClick={refresh}>
|
||||||
<CCol sm="6" xxl="6">
|
<CIcon content={cilSync} />
|
||||||
<CRow>
|
</CButton>
|
||||||
<CCol sm="1" xxl="5" />
|
</CPopover>
|
||||||
<CCol sm="4" xxl="2" className="text-right">
|
</div>
|
||||||
<CButton color="secondary" onClick={goToAnalysis}>
|
<div className="pl-2">
|
||||||
{t('wifi_analysis.title')}
|
<CButton color="primary" variant="outline" onClick={toggleLifetimeModal}>
|
||||||
</CButton>
|
Lifetime Statistics
|
||||||
</CCol>
|
</CButton>
|
||||||
<CCol sm="3" xxl="2" className="text-right">
|
</div>
|
||||||
<CButton color="secondary" onClick={toggleLatestModal}>
|
<div className="pl-2">
|
||||||
{t('statistics.show_latest')}
|
<CButton color="primary" variant="outline" onClick={toggleLatestModal}>
|
||||||
</CButton>
|
{t('statistics.show_latest')}
|
||||||
</CCol>
|
</CButton>
|
||||||
<CCol sm="3" xxl="2" className="text-right">
|
</div>
|
||||||
<CButton color="secondary" onClick={toggleLifetimeModal}>
|
<div>
|
||||||
Lifetime Statistics
|
<CButton color="primary" variant="outline" onClick={goToAnalysis}>
|
||||||
</CButton>
|
{t('wifi_analysis.title')}
|
||||||
</CCol>
|
</CButton>
|
||||||
<CCol sm="1" xxl="1" className="text-center">
|
</div>
|
||||||
<CPopover content={t('common.refresh')}>
|
<div className="text-value-lg mr-auto">{t('statistics.title')}</div>
|
||||||
<CButton color="secondary" onClick={refresh} size="sm">
|
</div>
|
||||||
<CIcon content={cilSync} />
|
|
||||||
</CButton>
|
|
||||||
</CPopover>
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
</CCol>
|
|
||||||
</CRow>
|
|
||||||
</CCardHeader>
|
</CCardHeader>
|
||||||
<CCardBody className="p-5">
|
<CCardBody className="p-5">
|
||||||
<StatisticsChartList />
|
<StatisticsChartList />
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ import {
|
|||||||
CSwitch,
|
CSwitch,
|
||||||
CCol,
|
CCol,
|
||||||
CRow,
|
CRow,
|
||||||
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilX } from '@coreui/icons';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import DatePicker from 'react-widgets/DatePicker';
|
import DatePicker from 'react-widgets/DatePicker';
|
||||||
@@ -82,8 +85,15 @@ const ActionModal = ({ show, toggleModal }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal show={show} onClose={toggleModal}>
|
<CModal show={show} onClose={toggleModal}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle>{t('reboot.title')}</CModalTitle>
|
<CModalTitle className="pl-1 pt-1">{t('reboot.title')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggleModal}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
{result === 'success' ? (
|
{result === 'success' ? (
|
||||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ import {
|
|||||||
CInputRadio,
|
CInputRadio,
|
||||||
CFormGroup,
|
CFormGroup,
|
||||||
CLabel,
|
CLabel,
|
||||||
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilX } from '@coreui/icons';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
@@ -256,8 +259,15 @@ const TraceModal = ({ show, toggleModal }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal show={show} onClose={toggleModal}>
|
<CModal show={show} onClose={toggleModal}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle>{t('trace.title')}</CModalTitle>
|
<CModalTitle className="pl-1 pt-1">{t('trace.title')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggleModal}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
{getBody()}
|
{getBody()}
|
||||||
</CModal>
|
</CModal>
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ import {
|
|||||||
CSwitch,
|
CSwitch,
|
||||||
CCol,
|
CCol,
|
||||||
CSpinner,
|
CSpinner,
|
||||||
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilX } from '@coreui/icons';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
@@ -124,8 +127,15 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CModal size="lg" show={show} onClose={toggleModal}>
|
<CModal size="lg" show={show} onClose={toggleModal}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader className="p-1">
|
||||||
<CModalTitle>{t('actions.wifi_scan')}</CModalTitle>
|
<CModalTitle className="pl-1 pt-1">{t('actions.wifi_scan')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggleModal}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
<CModalBody>
|
<CModalBody>
|
||||||
<div hidden={hideOptions || waiting}>
|
<div hidden={hideOptions || waiting}>
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
/* eslint-disable-rule prefer-destructuring */
|
/* eslint-disable-rule prefer-destructuring */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import { CButton, CModal, CModalHeader, CModalBody, CModalTitle, CPopover } from '@coreui/react';
|
||||||
CButton,
|
import CIcon from '@coreui/icons-react';
|
||||||
CModal,
|
import { cilX } from '@coreui/icons';
|
||||||
CModalHeader,
|
|
||||||
CModalBody,
|
|
||||||
CModalTitle,
|
|
||||||
CModalFooter,
|
|
||||||
} from '@coreui/react';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { prettyDate } from 'utils/helper';
|
import { prettyDate } from 'utils/helper';
|
||||||
import WifiChannelTable from './WifiChannelTable';
|
import WifiChannelTable from './WifiChannelTable';
|
||||||
@@ -48,21 +43,23 @@ const WifiScanResultModal = ({ show, toggle, scanResults, date }) => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<CModal size="lg" show={show} onClose={toggle}>
|
<CModal size="lg" show={show} onClose={toggle}>
|
||||||
<CModalHeader closeButton>
|
<CModalHeader>
|
||||||
<CModalTitle className="text-dark">
|
<CModalTitle className="text-dark">
|
||||||
{date !== '' ? prettyDate(date) : ''} {t('scan.results')}
|
{date !== '' ? prettyDate(date) : ''} {t('scan.results')}
|
||||||
</CModalTitle>
|
</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggle}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
<CModalBody>
|
<CModalBody>
|
||||||
{scanResults === null ? null : (
|
{scanResults === null ? null : (
|
||||||
<WifiChannelTable channels={parseThroughList(scanResults)} />
|
<WifiChannelTable channels={parseThroughList(scanResults)} />
|
||||||
)}
|
)}
|
||||||
</CModalBody>
|
</CModalBody>
|
||||||
<CModalFooter>
|
|
||||||
<CButton color="secondary" onClick={toggle}>
|
|
||||||
{t('common.close')}
|
|
||||||
</CButton>
|
|
||||||
</CModalFooter>
|
|
||||||
</CModal>
|
</CModal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ const TheLayout = () => {
|
|||||||
<PageContainer t={t} routes={routes} redirectTo="/devices" />
|
<PageContainer t={t} routes={routes} redirectTo="/devices" />
|
||||||
</ToastProvider>
|
</ToastProvider>
|
||||||
</div>
|
</div>
|
||||||
<Footer t={t} version="2.1.10" />
|
<Footer t={t} version={process.env.VERSION} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import React from 'react';
|
|||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { CRow, CCol } from '@coreui/react';
|
import { CRow, CCol } from '@coreui/react';
|
||||||
import DeviceHealth from 'components/DeviceHealth';
|
import DeviceHealth from 'components/DeviceHealth';
|
||||||
import DeviceConfiguration from 'components/DeviceConfiguration';
|
|
||||||
import DeviceStatusCard from 'components/DeviceStatusCard';
|
import DeviceStatusCard from 'components/DeviceStatusCard';
|
||||||
import CommandHistory from 'components/CommandHistory';
|
import CommandHistory from 'components/CommandHistory';
|
||||||
import DeviceLogs from 'components/DeviceLogs';
|
import DeviceLogs from 'components/DeviceLogs';
|
||||||
@@ -18,20 +17,25 @@ const DevicePage = () => {
|
|||||||
<div className="App">
|
<div className="App">
|
||||||
<DeviceProvider axiosInstance={axiosInstance} serialNumber={deviceId}>
|
<DeviceProvider axiosInstance={axiosInstance} serialNumber={deviceId}>
|
||||||
<CRow>
|
<CRow>
|
||||||
<CCol xs="12" lg="6">
|
<CCol>
|
||||||
<DeviceStatusCard />
|
<DeviceStatusCard />
|
||||||
<DeviceConfiguration />
|
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol xs="12" lg="6">
|
</CRow>
|
||||||
<DeviceLogs />
|
<CRow>
|
||||||
<DeviceHealth />
|
<CCol>
|
||||||
|
<CommandHistory />
|
||||||
|
</CCol>
|
||||||
|
<CCol>
|
||||||
<DeviceActionCard />
|
<DeviceActionCard />
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<CRow>
|
<CRow>
|
||||||
<CCol>
|
<CCol>
|
||||||
<DeviceStatisticsCard />
|
<DeviceStatisticsCard />
|
||||||
<CommandHistory />
|
</CCol>
|
||||||
|
<CCol>
|
||||||
|
<DeviceHealth />
|
||||||
|
<DeviceLogs />
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
</DeviceProvider>
|
</DeviceProvider>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { CCard, CCardBody } from '@coreui/react';
|
import { CCard, CCardBody, CCardHeader, CButton, CPopover } from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilSave } from '@coreui/icons';
|
||||||
import axiosInstance from 'utils/axiosInstance';
|
import axiosInstance from 'utils/axiosInstance';
|
||||||
import { testRegex } from 'utils/helper';
|
import { testRegex } from 'utils/helper';
|
||||||
import { useUser, EditMyProfile, useAuth, useToast } from 'ucentral-libs';
|
import { useUser, EditMyProfile, useAuth, useToast } from 'ucentral-libs';
|
||||||
@@ -122,10 +124,10 @@ const ProfilePage = () => {
|
|||||||
setNewAvatarFile(null);
|
setNewAvatarFile(null);
|
||||||
setFileInputKey(fileInputKey + 1);
|
setFileInputKey(fileInputKey + 1);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
addToast({
|
addToast({
|
||||||
title: t('user.update_failure_title'),
|
title: t('user.update_failure_title'),
|
||||||
body: t('user.update_failure'),
|
body: t('user.update_failure', { error: e.response?.data?.ErrorDescription }),
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
autohide: true,
|
autohide: true,
|
||||||
});
|
});
|
||||||
@@ -180,10 +182,10 @@ const ProfilePage = () => {
|
|||||||
autohide: true,
|
autohide: true,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
addToast({
|
addToast({
|
||||||
title: t('user.update_failure_title'),
|
title: t('user.update_failure_title'),
|
||||||
body: t('user.update_failure'),
|
body: t('user.update_failure', { error: e.response?.data?.ErrorDescription }),
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
autohide: true,
|
autohide: true,
|
||||||
});
|
});
|
||||||
@@ -260,12 +262,20 @@ const ProfilePage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CCard>
|
<CCard>
|
||||||
|
<CCardHeader>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.save')}>
|
||||||
|
<CButton onClick={updateUser} color="primary" variant="outline" disabled={loading}>
|
||||||
|
<CIcon content={cilSave} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
</CCardHeader>
|
||||||
<CCardBody>
|
<CCardBody>
|
||||||
<EditMyProfile
|
<EditMyProfile
|
||||||
t={t}
|
t={t}
|
||||||
user={userForm}
|
user={userForm}
|
||||||
updateUserWithId={updateWithId}
|
updateUserWithId={updateWithId}
|
||||||
saveUser={updateUser}
|
|
||||||
loading={loading}
|
loading={loading}
|
||||||
policies={policies}
|
policies={policies}
|
||||||
addNote={addNote}
|
addNote={addNote}
|
||||||
|
|||||||
@@ -45,7 +45,13 @@ const UserListPage = () => {
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
setUsers(response.data.users);
|
setUsers(response.data.users);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: t('user.error_fetching_users', { error: e.response?.data?.ErrorDescription }),
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -113,7 +119,13 @@ const UserListPage = () => {
|
|||||||
setUsersToDisplay(newUsers);
|
setUsersToDisplay(newUsers);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: t('user.error_fetching_users', { error: e.response?.data?.ErrorDescription }),
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -139,10 +151,10 @@ const UserListPage = () => {
|
|||||||
});
|
});
|
||||||
getUsers();
|
getUsers();
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
addToast({
|
addToast({
|
||||||
title: t('common.error'),
|
title: t('common.error'),
|
||||||
body: t('user.delete_failure'),
|
body: t('user.delete_failure', { error: e.response?.data?.ErrorDescription }),
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
autohide: true,
|
autohide: true,
|
||||||
});
|
});
|
||||||
@@ -186,6 +198,7 @@ const UserListPage = () => {
|
|||||||
usersPerPage={usersPerPage}
|
usersPerPage={usersPerPage}
|
||||||
setUsersPerPage={updateUsersPerPage}
|
setUsersPerPage={updateUsersPerPage}
|
||||||
pageCount={pageCount}
|
pageCount={pageCount}
|
||||||
|
currentPage={page.selected}
|
||||||
setPage={setPage}
|
setPage={setPage}
|
||||||
deleteUser={deleteUser}
|
deleteUser={deleteUser}
|
||||||
deleteLoading={deleteLoading}
|
deleteLoading={deleteLoading}
|
||||||
|
|||||||
@@ -14,8 +14,12 @@ import {
|
|||||||
CModal,
|
CModal,
|
||||||
CModalHeader,
|
CModalHeader,
|
||||||
CModalBody,
|
CModalBody,
|
||||||
|
CModalTitle,
|
||||||
CRow,
|
CRow,
|
||||||
|
CPopover,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
|
import CIcon from '@coreui/icons-react';
|
||||||
|
import { cilX } from '@coreui/icons';
|
||||||
|
|
||||||
const WifiAnalysisPage = () => {
|
const WifiAnalysisPage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -198,7 +202,7 @@ const WifiAnalysisPage = () => {
|
|||||||
<h5 className="mb-0">{t('common.device', { serialNumber: deviceId })}</h5>
|
<h5 className="mb-0">{t('common.device', { serialNumber: deviceId })}</h5>
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol className="text-right">
|
<CCol className="text-right">
|
||||||
<CButton color="secondary" onClick={toggleModal}>
|
<CButton color="primary" variant="outline" onClick={toggleModal}>
|
||||||
{t('wifi_analysis.network_diagram')}
|
{t('wifi_analysis.network_diagram')}
|
||||||
</CButton>
|
</CButton>
|
||||||
</CCol>
|
</CCol>
|
||||||
@@ -235,7 +239,16 @@ const WifiAnalysisPage = () => {
|
|||||||
</CCardBody>
|
</CCardBody>
|
||||||
</CCard>
|
</CCard>
|
||||||
<CModal size="xl" show={showModal} onClose={toggleModal}>
|
<CModal size="xl" show={showModal} onClose={toggleModal}>
|
||||||
<CModalHeader closeButton>{t('wifi_analysis.network_diagram')}</CModalHeader>
|
<CModalHeader className="p-1">
|
||||||
|
<CModalTitle className="pl-1 pt-1">{t('wifi_analysis.network_diagram')}</CModalTitle>
|
||||||
|
<div className="text-right">
|
||||||
|
<CPopover content={t('common.close')}>
|
||||||
|
<CButton color="primary" variant="outline" className="ml-2" onClick={toggleModal}>
|
||||||
|
<CIcon content={cilX} />
|
||||||
|
</CButton>
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
</CModalHeader>
|
||||||
<CModalBody>
|
<CModalBody>
|
||||||
{showModal ? (
|
{showModal ? (
|
||||||
<NetworkDiagram
|
<NetworkDiagram
|
||||||
|
|||||||
Reference in New Issue
Block a user