[WIFI-11454] Display restricted devices and certificate expiry date

Signed-off-by: Charles <charles.bourque96@gmail.com>
This commit is contained in:
Charles
2022-11-02 10:32:54 +00:00
parent 53a8cd8ee4
commit 616e4b6e0c
14 changed files with 308 additions and 13 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ucentral-client",
"version": "2.8.0(3)",
"version": "2.8.0(4)",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ucentral-client",
"version": "2.8.0(3)",
"version": "2.8.0(4)",
"license": "ISC",
"dependencies": {
"@chakra-ui/icons": "^2.0.11",

View File

@@ -1,6 +1,6 @@
{
"name": "ucentral-client",
"version": "2.8.0(3)",
"version": "2.8.0(4)",
"description": "",
"private": true,
"main": "index.tsx",

View File

@@ -593,6 +593,8 @@
"devices": {
"all": "Alles",
"associations": "Verbände",
"certificate_expires_in": "Zertifikat läuft ab in",
"certificate_expiry": "Zert. Läuft ab in",
"connected": "In Verbindung gebracht",
"create_errors": "Fehler beim Versuch, Geräte zu erstellen",
"create_success": " Geräte erfolgreich erstellt",
@@ -613,6 +615,7 @@
"notifications": "Gerätebenachrichtigungen",
"one": "Gerät",
"reassign_already_owned": "Geräte neu zuweisen, die bereits vorhanden sind und einem anderen Unternehmen/Veranstaltungsort/Abonnenten gehören?",
"restricted": "Beschränkt",
"sanity": "Gesundheit",
"start_import": "Geräteimport starten",
"test_batch": "Testen Sie Importdaten",
@@ -670,6 +673,7 @@
"version": "Ausführung"
},
"form": {
"captive_web_root_explanation": "Bitte verwenden Sie nur .tar-Dateien (keine komprimierten Dateien wie z. B. .targz)",
"certificate_file_explanation": "Bitte verwenden Sie eine .pem-Datei, die mit „-----BEGIN CERTIFICATE-----“ beginnt und mit „-----END CERTIFICATE-----“ endet.",
"invalid_cidr": "Ungültige CIDR-IPv4-Adresse. Beispiel: 192.168.0.1/12",
"invalid_email": "Ungültige E-Mail",
@@ -678,6 +682,7 @@
"invalid_hostname": "Ungültiger Hostname: Er darf nur aus alphanumerischen Zeichen und Bindestrichen bestehen",
"invalid_icon_lang": "Ungültige Sprache, sollte aus 3 Buchstaben bestehen (eng, fre, ger, ita usw.)",
"invalid_ieee": "Für dieses Verschlüsselungsprotokoll muss ieee80211w entweder „optional“ oder „erforderlich“ sein.",
"invalid_ieee_required": "ieee80211w muss für dieses Verschlüsselungsprotokoll „erforderlich“ sein",
"invalid_interfaces": "Ungültige Schnittstellen-JSON-Zeichenfolge. Bitte bestätigen Sie, dass Ihr Wert gültiges JSON ist und Schnittstellen als einzigen Schlüssel hat und dass der Schnittstellenwert ein Array ist. Beispiel: {\"interfaces\": []}",
"invalid_ipv4": "Ungültige IPv4-Adresse (Bsp.: 192.168.0.1 oder 192.168.0.1/16",
"invalid_ipv6": "Ungültige IPv6-Adresse (Bsp.: 2001:db8:3333:4444:5555:6666:7777:8888)",
@@ -853,6 +858,48 @@
"one": "Serviceklasse",
"other": "Serviceklassen"
},
"simulation": {
"cancel": "Simulation abbrechen",
"cancel_explanation": "Stoppen Sie die Simulation und löschen Sie ihren Datensatz",
"cancel_success": "Simulation beendet und Aufzeichnungen gelöscht!",
"client_interval": "Kundenintervall",
"concurrent_devices": "Gleichzeitige Geräte",
"controller": "Regler",
"current_live_devices": "Aktuelle Live-Geräte",
"delete_success": "Gelöschte Simulation!",
"duration": "Dauer",
"error_devices": "Fehler Geräte",
"healthcheck_interval": "Healthcheck-Intervall",
"infinite": "Unendlich",
"keep_alive": "Bleib am Leben",
"mac_prefix": "MAC-Präfix",
"max_associations": "max. Verbände",
"max_clients": "Max. Kunden",
"min_associations": "Mindest. Verbände",
"min_clients": "Mindest. Kunden",
"no_sim_running": "Derzeit läuft keine Simulation",
"one": "Simulation",
"other": "Simulationen",
"owner": "Inhaber",
"realtime_data": "Echtzeitdaten",
"realtime_messages": "Echtzeit-Nachrichten",
"reconnect_interval": "Wiederverbindungsintervall",
"result_delete_success": "Gelöschtes Ergebnis!",
"rx": "empfangen",
"rx_messages": "Rx-Meldungen",
"sim_currently_running": "Simulation \"{{sim}}\" läuft",
"sim_history": "{{sim}} Vorherige Läufe",
"start": "Simulation starten",
"start_success": "Simulationslauf gestartet!",
"state_interval": "Zustandsintervall",
"stop": "Simulation stoppen",
"stop_success": "Simulation gestoppt!",
"threads": "Themen",
"time_to_full": "Zeit für volle Geräte",
"tx": "Übertragen",
"tx_messages": "Tx-Nachrichten",
"view_previous_runs": "Vorherige Läufe anzeigen"
},
"statistics": {
"last_stats": "Letzte Statistik",
"memory": "Erinnerung"

View File

@@ -593,6 +593,8 @@
"devices": {
"all": "All",
"associations": "Associations",
"certificate_expires_in": "Certificate Expiry",
"certificate_expiry": "Cert. Expires In",
"connected": "Connected",
"create_errors": "errors while trying to create devices",
"create_success": " devices successfully created",
@@ -613,6 +615,7 @@
"notifications": "Device Notifications",
"one": "Device",
"reassign_already_owned": "Reassign devices which already exist and are owned by another entity/venue/subscriber?",
"restricted": "Restricted",
"sanity": "Sanity",
"start_import": "Start Device Importation",
"test_batch": "Test Import Data",
@@ -670,6 +673,7 @@
"version": "Version"
},
"form": {
"captive_web_root_explanation": "Please use .tar files only (no compressed files like .targz, for example)",
"certificate_file_explanation": "Please use a .pem file that starts with \"-----BEGIN CERTIFICATE-----\" and ends with \"-----END CERTIFICATE-----\"",
"invalid_cidr": "Invalid CIDR IPv4 address. Example: 192.168.0.1/12",
"invalid_email": "Invalid Email",
@@ -678,6 +682,7 @@
"invalid_hostname": "Invalid hostname: it needs to be composed of alphanumeric characters and dashes only",
"invalid_icon_lang": "Invalid language, it should be in a 3-letter format (eng, fre, ger, ita, etc.)",
"invalid_ieee": "For this encryption protocol, ieee80211w needs to be either 'optional' or 'required'",
"invalid_ieee_required": "ieee80211w needs to be 'required' for this encryption protocol",
"invalid_interfaces": "Invalid Interfaces JSON string. Please confirm that your value is: valid JSON and has interfaces as its only key and that the interfaces value is an array. Example: {\"interfaces\": []}",
"invalid_ipv4": "Invalid IPv4 address (ex.: 192.168.0.1 or 192.168.0.1/16",
"invalid_ipv6": "Invalid IPv6 address (ex.: 2001:db8:3333:4444:5555:6666:7777:8888)",
@@ -853,6 +858,48 @@
"one": "Service Class",
"other": "Service Classes"
},
"simulation": {
"cancel": "Cancel Simulation",
"cancel_explanation": "Stop the simulation and erase its record",
"cancel_success": "Stopped simulation and erased its record!",
"client_interval": "Client Interval",
"concurrent_devices": "Concurrent Devices",
"controller": "Controller",
"current_live_devices": "Current Live Devices",
"delete_success": "Deleted Simulation!",
"duration": "Duration",
"error_devices": "Error Devices",
"healthcheck_interval": "Healthcheck Interval",
"infinite": "Infinite",
"keep_alive": "Keep Alive",
"mac_prefix": "MAC Prefix",
"max_associations": "Max. Associations",
"max_clients": "Max. Clients",
"min_associations": "Min. Associations",
"min_clients": "Min. Clients",
"no_sim_running": "No simulation currently running",
"one": "Simulation",
"other": "Simulations",
"owner": "Owner",
"realtime_data": "Real-Time Data",
"realtime_messages": "Real-Time Messages",
"reconnect_interval": "Reconnect Interval",
"result_delete_success": "Deleted Result!",
"rx": "Received",
"rx_messages": "Rx Messages",
"sim_currently_running": "Simulation \"{{sim}}\" in progress",
"sim_history": "{{sim}} Previous Runs",
"start": "Start Simulation",
"start_success": "Started simulation run!",
"state_interval": "State Interval",
"stop": "Stop Simulation",
"stop_success": "Stopped simulation!",
"threads": "Threads",
"time_to_full": "Time to full devices",
"tx": "Transmitted",
"tx_messages": "Tx Messages",
"view_previous_runs": "View Previous Runs"
},
"statistics": {
"last_stats": "Last Statistics",
"memory": "Memory"

View File

@@ -593,6 +593,8 @@
"devices": {
"all": "TODOS",
"associations": "Asociaciones",
"certificate_expires_in": "El certificado caduca en",
"certificate_expiry": "Cert. Expira en",
"connected": "Conectado",
"create_errors": "errores al intentar crear dispositivos",
"create_success": " dispositivos creados con éxito",
@@ -613,6 +615,7 @@
"notifications": "notificaciones de dispositivos",
"one": "Dispositivo",
"reassign_already_owned": "¿Reasignar dispositivos que ya existen y son propiedad de otra entidad/lugar/suscriptor?",
"restricted": "Restringido",
"sanity": "Cordura",
"start_import": "Iniciar la importación de dispositivos",
"test_batch": "Datos de importación de prueba",
@@ -670,6 +673,7 @@
"version": "Versión"
},
"form": {
"captive_web_root_explanation": "Utilice únicamente archivos .tar (no archivos comprimidos como .targz, por ejemplo)",
"certificate_file_explanation": "Utilice un archivo .pem que comience con \"-----BEGIN CERTIFICATE-----\" y termine con \"-----END CERTIFICATE-----\"",
"invalid_cidr": "Dirección IPv4 CIDR no válida. Ejemplo: 192.168.0.1/12",
"invalid_email": "Email inválido",
@@ -678,6 +682,7 @@
"invalid_hostname": "Nombre de host no válido: debe estar compuesto solo de caracteres alfanuméricos y guiones",
"invalid_icon_lang": "Idioma no válido, debe estar en un formato de 3 letras (eng, fre, ger, ita, etc.)",
"invalid_ieee": "Para este protocolo de encriptación, ieee80211w debe ser 'opcional' u 'requerido'",
"invalid_ieee_required": "ieee80211w debe ser 'requerido' para este protocolo de encriptación",
"invalid_interfaces": "Cadena JSON de interfaces no válida. Confirme que su valor es: JSON válido y tiene interfaces como su única clave y que el valor de las interfaces es una matriz. Ejemplo: {\"interfaces\": []}",
"invalid_ipv4": "Dirección IPv4 no válida (ej.: 192.168.0.1 o 192.168.0.1/16",
"invalid_ipv6": "Dirección IPv6 no válida (ej.: 2001:db8:3333:4444:5555:6666:7777:8888)",
@@ -853,6 +858,48 @@
"one": "Clase de servicio",
"other": "Clases de servicio"
},
"simulation": {
"cancel": "Cancelar simulación",
"cancel_explanation": "Detener la simulación y borrar su registro",
"cancel_success": "¡Detuvo la simulación y borró su registro!",
"client_interval": "Intervalo de cliente",
"concurrent_devices": "Dispositivos concurrentes",
"controller": "Controlador",
"current_live_devices": "Dispositivos activos actuales",
"delete_success": "¡Simulación eliminada!",
"duration": "Duración",
"error_devices": "Dispositivos de error",
"healthcheck_interval": "Intervalo de comprobación de estado",
"infinite": "infinito",
"keep_alive": "Mantener viva",
"mac_prefix": "Prefijo MAC",
"max_associations": "Max. Asociaciones",
"max_clients": "Max. Clientela",
"min_associations": "Min. Asociaciones",
"min_clients": "Min. Clientela",
"no_sim_running": "No hay ninguna simulación actualmente en ejecución",
"one": "Simulación",
"other": "Simulaciones",
"owner": "Propietario",
"realtime_data": "Datos en Tiempo real",
"realtime_messages": "Mensajes en tiempo real",
"reconnect_interval": "Intervalo de reconexión",
"result_delete_success": "¡Resultado eliminado!",
"rx": "recibido",
"rx_messages": "Mensajes prescritos",
"sim_currently_running": "Simulación \"{{sim}}\" en curso",
"sim_history": "{{sim}} ejecuciones anteriores",
"start": "Iniciar simulación",
"start_success": "¡Ejecución de simulación iniciada!",
"state_interval": "Intervalo de estado",
"stop": "Detener simulación",
"stop_success": "Simulación detenida!",
"threads": "Trapos",
"time_to_full": "Tiempo para dispositivos completos",
"tx": "Transmitido",
"tx_messages": "Mensajes TX",
"view_previous_runs": "Ver carreras anteriores"
},
"statistics": {
"last_stats": "Últimas estadísticas",
"memory": "Memoria"

View File

@@ -593,6 +593,8 @@
"devices": {
"all": "Tout",
"associations": "Les associations",
"certificate_expires_in": "Le certificat expire dans",
"certificate_expiry": "Cert. Expire dans",
"connected": "Connecté",
"create_errors": "erreurs lors de la tentative de création d'appareils",
"create_success": " appareils créés avec succès",
@@ -613,6 +615,7 @@
"notifications": "notifications de l'appareil",
"one": "Dispositif",
"reassign_already_owned": "Réattribuer des appareils qui existent déjà et qui appartiennent à une autre entité/salle/abonné ?",
"restricted": "Limité",
"sanity": "Santé mentale",
"start_import": "Démarrer l'importation de l'appareil",
"test_batch": "Tester les données d'importation",
@@ -670,6 +673,7 @@
"version": "Version"
},
"form": {
"captive_web_root_explanation": "Veuillez utiliser uniquement des fichiers .tar (pas de fichiers compressés comme .targz, par exemple)",
"certificate_file_explanation": "Veuillez utiliser un fichier .pem qui commence par \"-----BEGIN CERTIFICATE-----\" et se termine par \"-----END CERTIFICATE-----\"",
"invalid_cidr": "Adresse IPv4 CIDR non valide. Exemple : 192.168.0.1/12",
"invalid_email": "Email Invalide",
@@ -678,6 +682,7 @@
"invalid_hostname": "Nom d'hôte non valide : il doit être composé uniquement de caractères alphanumériques et de tirets",
"invalid_icon_lang": "Langue non valide, elle doit être dans un format à 3 lettres (eng, fre, ger, ita, etc.)",
"invalid_ieee": "Pour ce protocole de cryptage, ieee80211w doit être soit 'facultatif' soit 'obligatoire'",
"invalid_ieee_required": "ieee80211w doit être \"obligatoire\" pour ce protocole de cryptage",
"invalid_interfaces": "Chaîne JSON d'interfaces non valide. Veuillez confirmer que votre valeur est : JSON valide et a des interfaces comme seule clé et que la valeur des interfaces est un tableau. Exemple : {\"interfaces\": []}",
"invalid_ipv4": "Adresse IPv4 invalide (ex. : 192.168.0.1 ou 192.168.0.1/16",
"invalid_ipv6": "Adresse IPv6 invalide (ex. : 2001:db8:3333:4444:5555:6666:7777:8888)",
@@ -853,6 +858,48 @@
"one": "Classe de service",
"other": "Catégories de services"
},
"simulation": {
"cancel": "Annuler la simulation",
"cancel_explanation": "Arrêtez la simulation et effacez son enregistrement",
"cancel_success": "Simulation arrêtée et efface son enregistrement !",
"client_interval": "Intervalle client",
"concurrent_devices": "Périphériques simultanés",
"controller": "Manette",
"current_live_devices": "Appareils en direct actuels",
"delete_success": "Simulation supprimée !",
"duration": "Durée",
"error_devices": "Périphériques d'erreur",
"healthcheck_interval": "Intervalle de vérification de l'état",
"infinite": "Infini",
"keep_alive": "Rester en vie",
"mac_prefix": "Préfixe MAC",
"max_associations": "Max. Les associations",
"max_clients": "Max. Clients",
"min_associations": "Min. Les associations",
"min_clients": "Min. Clients",
"no_sim_running": "Aucune simulation en cours",
"one": "simulation",
"other": "Simulations",
"owner": "Propriétaire",
"realtime_data": "Données en temps réel",
"realtime_messages": "Messages en temps réel",
"reconnect_interval": "Intervalle de reconnexion",
"result_delete_success": "Résultat supprimé !",
"rx": "reçu",
"rx_messages": "Messages reçus",
"sim_currently_running": "Simulation \"{{sim}}\" en cours",
"sim_history": "{{sim}} courses précédentes",
"start": "Démarrer la simulation",
"start_success": "Lancement de la simulation !",
"state_interval": "Intervalle d'état",
"stop": "Arrêter la simulation",
"stop_success": "Simulation arrêtée !",
"threads": "Fils",
"time_to_full": "Temps pour les appareils pleins",
"tx": "Transmis",
"tx_messages": "Messages de transmission",
"view_previous_runs": "Voir les courses précédentes"
},
"statistics": {
"last_stats": "Dernières statistiques",
"memory": "mémoire"

View File

@@ -593,6 +593,8 @@
"devices": {
"all": "Todos",
"associations": "Associações",
"certificate_expires_in": "Certificado expira em",
"certificate_expiry": "Certificado expira em",
"connected": "Conectado",
"create_errors": "erros ao tentar criar dispositivos",
"create_success": " dispositivos criados com sucesso",
@@ -613,6 +615,7 @@
"notifications": "Notificações do dispositivo",
"one": "Dispositivo",
"reassign_already_owned": "Reatribuir dispositivos que já existem e são de propriedade de outra entidade/local/assinante?",
"restricted": "Restrito",
"sanity": "Sanidade",
"start_import": "Iniciar importação de dispositivos",
"test_batch": "Dados de importação de teste",
@@ -670,6 +673,7 @@
"version": "Versão"
},
"form": {
"captive_web_root_explanation": "Por favor, use apenas arquivos .tar (sem arquivos compactados como .targz, por exemplo)",
"certificate_file_explanation": "Use um arquivo .pem que comece com \"-----BEGIN CERTIFICATE-----\" e termine com \"-----END CERTIFICATE-----\"",
"invalid_cidr": "Endereço CIDR IPv4 inválido. Exemplo: 192.168.0.1/12",
"invalid_email": "E-mail inválido",
@@ -678,6 +682,7 @@
"invalid_hostname": "Nome de host inválido: precisa ser composto apenas de caracteres alfanuméricos e traços",
"invalid_icon_lang": "Idioma inválido, deve estar em formato de 3 letras (eng, fre, ger, ita, etc.)",
"invalid_ieee": "Para este protocolo de criptografia, ieee80211w precisa ser 'opcional' ou 'obrigatório'",
"invalid_ieee_required": "ieee80211w precisa ser 'obrigatório' para este protocolo de criptografia",
"invalid_interfaces": "Sequência JSON de interfaces inválida. Confirme se seu valor é: JSON válido e tem interfaces como sua única chave e que o valor de interfaces é uma matriz. Exemplo: {\"interfaces\": []}",
"invalid_ipv4": "Endereço IPv4 inválido (ex.: 192.168.0.1 ou 192.168.0.1/16",
"invalid_ipv6": "Endereço IPv6 inválido (ex.: 2001:db8:3333:4444:5555:6666:7777:8888)",
@@ -853,6 +858,48 @@
"one": "Classe de serviço",
"other": "Classes de serviço"
},
"simulation": {
"cancel": "Cancelar simulação",
"cancel_explanation": "Pare a simulação e apague seu registro",
"cancel_success": "Parou a simulação e apagou seu registro!",
"client_interval": "Intervalo do Cliente",
"concurrent_devices": "Dispositivos Simultâneos",
"controller": "Controlador",
"current_live_devices": "Dispositivos ativos atuais",
"delete_success": "Simulação excluída!",
"duration": "Duração",
"error_devices": "Dispositivos de Erro",
"healthcheck_interval": "Intervalo de verificação de saúde",
"infinite": "Infinito",
"keep_alive": "Mantenha vivo",
"mac_prefix": "Prefixo MAC",
"max_associations": "Máx. Associações",
"max_clients": "Máx. Clientes",
"min_associations": "Min. Associações",
"min_clients": "Min. Clientes",
"no_sim_running": "Nenhuma simulação em execução no momento",
"one": "Simulação",
"other": "Simulações",
"owner": "Proprietário",
"realtime_data": "Dados em tempo real",
"realtime_messages": "Mensagens em tempo real",
"reconnect_interval": "Intervalo de reconexão",
"result_delete_success": "Resultado deletado!",
"rx": "recebido",
"rx_messages": "Mensagens Rx",
"sim_currently_running": "Simulação \"{{sim}}\" em andamento",
"sim_history": "{{sim}} execuções anteriores",
"start": "Iniciar simulação",
"start_success": "Corrida de simulação iniciada!",
"state_interval": "Intervalo de estado",
"stop": "Parar simulação",
"stop_success": "Simulação parada!",
"threads": "Tópicos",
"time_to_full": "Tempo para dispositivos completos",
"tx": "Transmitido",
"tx_messages": "Mensagens Tx",
"view_previous_runs": "Ver execuções anteriores"
},
"statistics": {
"last_stats": "Últimas estatísticas",
"memory": "Memória"

View File

@@ -2,9 +2,17 @@ import React from 'react';
import { Tooltip } from '@chakra-ui/react';
import { compactDate, formatDaysAgo } from 'helpers/dateFormatting';
const FormattedDate: React.FC<{ date: number }> = ({ date }) => (
<Tooltip hasArrow placement="top" label={compactDate(date)}>
{date === 0 ? '-' : formatDaysAgo(date)}
type Props = { date?: number; hidePrefix?: boolean };
const getDaysAgo = ({ date, hidePrefix }: { date?: number; hidePrefix?: boolean }) => {
if (!date || date === 0) return '-';
return hidePrefix ? formatDaysAgo(date).split(' ').slice(1).join(' ') : formatDaysAgo(date);
};
const FormattedDate = ({ date, hidePrefix }: Props) => (
<Tooltip hasArrow placement="top" label={compactDate(date ?? 0)}>
{getDaysAgo({ date, hidePrefix })}
</Tooltip>
);

View File

@@ -43,6 +43,7 @@ export type DeviceWithStatus = {
associations_5G: number;
compatible: string;
connected: boolean;
certificateExpiryDate?: number;
createdTimestamp: number;
devicePassword: string;
deviceType: 'AP' | 'SWITCH' | 'IOT' | 'MESH';
@@ -62,6 +63,7 @@ export type DeviceWithStatus = {
modified: number;
notes: Note[];
owner: string;
restrictedDevice: boolean;
rxBytes: number;
serialNumber: string;
subscriber: string;
@@ -124,6 +126,7 @@ export type DeviceStatus = {
associations_2G: number;
associations_5G: number;
connected: boolean;
certificateExpiryDate: number;
connectionCompletionTime: number;
firmware: string;
ipAddress: string;
@@ -245,7 +248,7 @@ export const useDeleteDevice = ({ serialNumber }: { serialNumber: string }) => {
return useMutation(deleteDevice, {
onSuccess: () => {
queryClient.invalidateQueries('devices');
queryClient.invalidateQueries(['devices']);
queryClient.invalidateQueries(['device', serialNumber]);
},
});
@@ -396,7 +399,7 @@ export const useUpdateDevice = ({ serialNumber }: { serialNumber: string }) => {
return useMutation(modifyDevice, {
onSuccess: () => {
queryClient.invalidateQueries('devices');
queryClient.invalidateQueries(['devices']);
queryClient.invalidateQueries(['device', serialNumber]);
},
});

View File

@@ -21,6 +21,7 @@ export interface GatewayDevice {
modified: number;
notes: Note[];
owner: string;
restrictedDevice: boolean;
serialNumber: string;
subscriber: string;
venue: string;

View File

@@ -106,6 +106,14 @@ const DeviceSummary = ({ serialNumber }: Props) => {
<Heading size="sm">{t('analytics.memory')}:</Heading>
</GridItem>
<GridItem colSpan={1}>{getMemory()}</GridItem>
<GridItem colSpan={1} alignContent="center" alignItems="center">
<Heading size="sm">{t('devices.certificate_expires_in')}:</Heading>
</GridItem>
<GridItem colSpan={1}>
{getStatus.data?.certificateExpiryDate && (
<FormattedDate date={getStatus.data?.certificateExpiryDate} hidePrefix />
)}
</GridItem>
</Grid>
</Flex>
</CardBody>

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { Box, Heading, HStack, Spacer, Tag, TagLabel, TagLeftIcon, Tooltip, useDisclosure } from '@chakra-ui/react';
import { Heart, HeartBreak, WifiHigh, WifiSlash } from 'phosphor-react';
import { Heart, HeartBreak, LockSimple, WifiHigh, WifiSlash } from 'phosphor-react';
import { useTranslation } from 'react-i18next';
import Masonry from 'react-masonry-css';
import DeviceDetails from './Details';
@@ -97,6 +97,12 @@ const DevicePageWrapper = ({ serialNumber }: Props) => {
<Heading size="md">{serialNumber}</Heading>
{connectedTag}
{healthTag}
{getDevice.data?.restrictedDevice && (
<Tag size="lg" colorScheme="gray">
<TagLeftIcon boxSize="18px" as={LockSimple} />
<TagLabel>{t('devices.restricted')}</TagLabel>
</Tag>
)}
</HStack>
<Spacer />
<HStack spacing={2}>

View File

@@ -1,5 +1,6 @@
import * as React from 'react';
import { Box, Button, Heading, Image, Spacer, Tooltip, useDisclosure } from '@chakra-ui/react';
import { LockSimple } from 'phosphor-react';
import ReactCountryFlag from 'react-country-flag';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
@@ -115,7 +116,7 @@ const DeviceListCard = () => {
<Tooltip
label={`${device.verifiedCertificate} - ${
device.connected ? t('common.connected') : t('common.disconnected')
}`}
} ${device.restrictedDevice ? `- ${t('devices.restricted')}` : ''}`}
>
{ICONS[device.deviceType]}
</Tooltip>
@@ -130,6 +131,26 @@ const DeviceListCard = () => {
borderColor="gray.200"
borderWidth={1}
/>
{device.restrictedDevice && (
<Box
w="0.95em"
h="0.95em"
borderRadius="full"
position="absolute"
bg="blue.100"
left={-1}
top={0}
borderColor="gray.200"
borderWidth={1}
>
<LockSimple
size={12}
style={{
color: 'black',
}}
/>
</Box>
)}
</Box>
),
[],
@@ -152,8 +173,12 @@ const DeviceListCard = () => {
[],
);
const dateCell = React.useCallback(
(v: number | string) =>
v !== undefined && typeof v === 'number' && v !== 0 ? <FormattedDate date={v as number} /> : '-',
(v?: number | string, hidePrefix?: boolean) =>
v !== undefined && typeof v === 'number' && v !== 0 ? (
<FormattedDate date={v as number} hidePrefix={hidePrefix} />
) : (
'-'
),
[],
);
const firmwareCell = React.useCallback(
@@ -303,6 +328,15 @@ const DeviceListCard = () => {
customWidth: '50px',
disableSortBy: true,
},
{
id: 'certificateExpiryDate',
Header: t('devices.certificate_expiry'),
Footer: '',
accessor: 'certificateExpiryDate',
Cell: (v) => dateCell(v.cell.row.original.certificateExpiryDate, true),
customWidth: '50px',
disableSortBy: true,
},
{
id: 'actions',
Header: t('common.actions'),

View File

@@ -43,7 +43,7 @@ const SystemPage = () => {
<Card mb={4} py={2} px={4}>
<CardHeader>
<Heading size="md" my="auto">
{t('controller.firmware.endpoints')} ({endpoints?.length ?? 0})
{t('controller.firmware.endpoints')}
</Heading>
<Spacer />
<RefreshButton onClick={refetch} isFetching={isFetching} />