mirror of
https://github.com/Telecominfraproject/wlan-cloud-owprov-ui.git
synced 2025-11-02 03:27:56 +00:00
[WIFI-11706] Fix for missing analytics in venue page
Signed-off-by: Charles <charles.bourque96@gmail.com>
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "wlan-cloud-owprov-ui",
|
"name": "wlan-cloud-owprov-ui",
|
||||||
"version": "2.8.0(13)",
|
"version": "2.8.0(17)",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "wlan-cloud-owprov-ui",
|
"name": "wlan-cloud-owprov-ui",
|
||||||
"version": "2.8.0(13)",
|
"version": "2.8.0(17)",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chakra-ui/icons": "^2.0.11",
|
"@chakra-ui/icons": "^2.0.11",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wlan-cloud-owprov-ui",
|
"name": "wlan-cloud-owprov-ui",
|
||||||
"version": "2.8.0(13)",
|
"version": "2.8.0(17)",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.tsx",
|
"main": "index.tsx",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
"live_view_help": "Hilfe zur Live-Ansicht",
|
"live_view_help": "Hilfe zur Live-Ansicht",
|
||||||
"memory": "Erinnerung",
|
"memory": "Erinnerung",
|
||||||
"memory_used": "Verwendeter Speicher",
|
"memory_used": "Verwendeter Speicher",
|
||||||
|
"missing_board": "Die Analytics-Überwachung an diesem Veranstaltungsort ist nicht mehr aktiv. Bitte starten Sie die Überwachung über das obere Menü neu",
|
||||||
"mode": "Modus",
|
"mode": "Modus",
|
||||||
"noise": "Lärm",
|
"noise": "Lärm",
|
||||||
"packets": "Pakete",
|
"packets": "Pakete",
|
||||||
@@ -613,6 +614,7 @@
|
|||||||
"import_explanation": "Für den Massenimport von Geräten müssen Sie eine CSV-Datei mit den folgenden Spalten verwenden: SerialNumber, DeviceType, Name, Description, Note",
|
"import_explanation": "Für den Massenimport von Geräten müssen Sie eine CSV-Datei mit den folgenden Spalten verwenden: SerialNumber, DeviceType, Name, Description, Note",
|
||||||
"invalid_serial_number": "Ungültige Seriennummer (muss 12 HEX-Zeichen lang sein)",
|
"invalid_serial_number": "Ungültige Seriennummer (muss 12 HEX-Zeichen lang sein)",
|
||||||
"new_devices": "Neue Geräte",
|
"new_devices": "Neue Geräte",
|
||||||
|
"no_model_image": "Kein Modellbild gefunden",
|
||||||
"not_connected": "Nicht verbunden",
|
"not_connected": "Nicht verbunden",
|
||||||
"not_found_gateway": "Fehler: Gerät hat sich noch nicht mit dem Gateway verbunden",
|
"not_found_gateway": "Fehler: Gerät hat sich noch nicht mit dem Gateway verbunden",
|
||||||
"notifications": "Gerätebenachrichtigungen",
|
"notifications": "Gerätebenachrichtigungen",
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
"live_view_help": "Live View Help",
|
"live_view_help": "Live View Help",
|
||||||
"memory": "Memory",
|
"memory": "Memory",
|
||||||
"memory_used": "Memory Used",
|
"memory_used": "Memory Used",
|
||||||
|
"missing_board": "Analytics monitoring on this venue is no longer active, please restart monitoring using the top menu",
|
||||||
"mode": "Mode",
|
"mode": "Mode",
|
||||||
"noise": "Noise",
|
"noise": "Noise",
|
||||||
"packets": "Packets",
|
"packets": "Packets",
|
||||||
@@ -613,6 +614,7 @@
|
|||||||
"import_explanation": "To bulk import devices, you need to use a CSV file with the following columns: SerialNumber, DeviceType, Name, Description, Note",
|
"import_explanation": "To bulk import devices, you need to use a CSV file with the following columns: SerialNumber, DeviceType, Name, Description, Note",
|
||||||
"invalid_serial_number": "Invalid Serial Number (needs to be 12 HEX chars)",
|
"invalid_serial_number": "Invalid Serial Number (needs to be 12 HEX chars)",
|
||||||
"new_devices": "new devices",
|
"new_devices": "new devices",
|
||||||
|
"no_model_image": "No Model Image Found",
|
||||||
"not_connected": "Not Connected",
|
"not_connected": "Not Connected",
|
||||||
"not_found_gateway": "Error: device has not yet connected to the controller",
|
"not_found_gateway": "Error: device has not yet connected to the controller",
|
||||||
"notifications": "Device Notifications",
|
"notifications": "Device Notifications",
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
"live_view_help": "Ayuda de visualización en vivo",
|
"live_view_help": "Ayuda de visualización en vivo",
|
||||||
"memory": "Memoria",
|
"memory": "Memoria",
|
||||||
"memory_used": "Memoria usada",
|
"memory_used": "Memoria usada",
|
||||||
|
"missing_board": "El monitoreo analítico en este lugar ya no está activo, reinicie el monitoreo usando el menú superior",
|
||||||
"mode": "Modo",
|
"mode": "Modo",
|
||||||
"noise": "Ruido",
|
"noise": "Ruido",
|
||||||
"packets": "Paquetes",
|
"packets": "Paquetes",
|
||||||
@@ -613,6 +614,7 @@
|
|||||||
"import_explanation": "Para importar dispositivos de forma masiva, debe usar un archivo CSV con las siguientes columnas: Número de serie, Tipo de dispositivo, Nombre, Descripción, Nota",
|
"import_explanation": "Para importar dispositivos de forma masiva, debe usar un archivo CSV con las siguientes columnas: Número de serie, Tipo de dispositivo, Nombre, Descripción, Nota",
|
||||||
"invalid_serial_number": "Número de serie no válido (debe tener 12 caracteres HEX)",
|
"invalid_serial_number": "Número de serie no válido (debe tener 12 caracteres HEX)",
|
||||||
"new_devices": "Nuevos dispositivos",
|
"new_devices": "Nuevos dispositivos",
|
||||||
|
"no_model_image": "No se encontró ninguna imagen de modelo",
|
||||||
"not_connected": "No conectado",
|
"not_connected": "No conectado",
|
||||||
"not_found_gateway": "Error: el dispositivo aún no se ha conectado a la puerta de enlace",
|
"not_found_gateway": "Error: el dispositivo aún no se ha conectado a la puerta de enlace",
|
||||||
"notifications": "notificaciones de dispositivos",
|
"notifications": "notificaciones de dispositivos",
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
"live_view_help": "Aide sur l'affichage en direct",
|
"live_view_help": "Aide sur l'affichage en direct",
|
||||||
"memory": "mémoire",
|
"memory": "mémoire",
|
||||||
"memory_used": "Mémoire utilisée",
|
"memory_used": "Mémoire utilisée",
|
||||||
|
"missing_board": "La surveillance analytique sur ce lieu n'est plus active, veuillez redémarrer la surveillance en utilisant le menu du haut",
|
||||||
"mode": "Mode",
|
"mode": "Mode",
|
||||||
"noise": "Bruit",
|
"noise": "Bruit",
|
||||||
"packets": "Paquets",
|
"packets": "Paquets",
|
||||||
@@ -613,6 +614,7 @@
|
|||||||
"import_explanation": "Pour importer en masse des appareils, vous devez utiliser un fichier CSV avec les colonnes suivantes : SerialNumber, DeviceType, Name, Description, Note",
|
"import_explanation": "Pour importer en masse des appareils, vous devez utiliser un fichier CSV avec les colonnes suivantes : SerialNumber, DeviceType, Name, Description, Note",
|
||||||
"invalid_serial_number": "Numéro de série non valide (doit être composé de 12 caractères HEX)",
|
"invalid_serial_number": "Numéro de série non valide (doit être composé de 12 caractères HEX)",
|
||||||
"new_devices": "nouveaux appareils",
|
"new_devices": "nouveaux appareils",
|
||||||
|
"no_model_image": "Aucune image de modèle trouvée",
|
||||||
"not_connected": "Pas connecté",
|
"not_connected": "Pas connecté",
|
||||||
"not_found_gateway": "Erreur : l'appareil n'est pas encore connecté à la passerelle",
|
"not_found_gateway": "Erreur : l'appareil n'est pas encore connecté à la passerelle",
|
||||||
"notifications": "notifications de l'appareil",
|
"notifications": "notifications de l'appareil",
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
"live_view_help": "Ajuda da visualização ao vivo",
|
"live_view_help": "Ajuda da visualização ao vivo",
|
||||||
"memory": "Memória",
|
"memory": "Memória",
|
||||||
"memory_used": "Memória Usada",
|
"memory_used": "Memória Usada",
|
||||||
|
"missing_board": "O monitoramento analítico neste local não está mais ativo, reinicie o monitoramento usando o menu superior",
|
||||||
"mode": "Modo",
|
"mode": "Modo",
|
||||||
"noise": "Barulho",
|
"noise": "Barulho",
|
||||||
"packets": "Pacotes",
|
"packets": "Pacotes",
|
||||||
@@ -613,6 +614,7 @@
|
|||||||
"import_explanation": "Para importar dispositivos em massa, você precisa usar um arquivo CSV com as seguintes colunas: SerialNumber, DeviceType, Name, Description, Note",
|
"import_explanation": "Para importar dispositivos em massa, você precisa usar um arquivo CSV com as seguintes colunas: SerialNumber, DeviceType, Name, Description, Note",
|
||||||
"invalid_serial_number": "Número de série inválido (precisa ter 12 caracteres HEX)",
|
"invalid_serial_number": "Número de série inválido (precisa ter 12 caracteres HEX)",
|
||||||
"new_devices": "novos dispositivos",
|
"new_devices": "novos dispositivos",
|
||||||
|
"no_model_image": "Nenhuma imagem de modelo encontrada",
|
||||||
"not_connected": "Não conectado",
|
"not_connected": "Não conectado",
|
||||||
"not_found_gateway": "Erro: o dispositivo ainda não se conectou ao gateway",
|
"not_found_gateway": "Erro: o dispositivo ainda não se conectou ao gateway",
|
||||||
"notifications": "Notificações do dispositivo",
|
"notifications": "Notificações do dispositivo",
|
||||||
|
|||||||
@@ -1,45 +1,259 @@
|
|||||||
import { useToast } from '@chakra-ui/react';
|
import { useToast } from '@chakra-ui/react';
|
||||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
import { AxiosError } from 'axios';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { AxiosError } from 'models/Axios';
|
||||||
|
import { Note } from 'models/Note';
|
||||||
import { PageInfo, SortInfo } from 'models/Table';
|
import { PageInfo, SortInfo } from 'models/Table';
|
||||||
import { axiosAnalytics } from 'utils/axiosInstances';
|
import { axiosAnalytics } from 'utils/axiosInstances';
|
||||||
|
|
||||||
|
export type AnalyticsBoardDevice = {
|
||||||
|
associations_2g: number;
|
||||||
|
associations_5g: number;
|
||||||
|
associations_6g: number;
|
||||||
|
boardId: string;
|
||||||
|
connected: boolean;
|
||||||
|
connectionIp: string;
|
||||||
|
deviceType: string;
|
||||||
|
health: number;
|
||||||
|
lastConnection: number;
|
||||||
|
lastContact: number;
|
||||||
|
lastDisconnection: number;
|
||||||
|
lastFirmware: string;
|
||||||
|
lastFirmwareUpdate: number;
|
||||||
|
lastHealth: number;
|
||||||
|
lastPing: number;
|
||||||
|
lastState: number;
|
||||||
|
locale: string;
|
||||||
|
memory: number;
|
||||||
|
pings: number;
|
||||||
|
serialNumber: string;
|
||||||
|
states: number;
|
||||||
|
type: string;
|
||||||
|
uptime: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnalyticsBoardDevicesApiResponse = {
|
||||||
|
devices: AnalyticsBoardDevice[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnalyticsBoardApiResponse = {
|
||||||
|
created: number;
|
||||||
|
description: string;
|
||||||
|
id: string;
|
||||||
|
modified: number;
|
||||||
|
name: string;
|
||||||
|
notes: Note[];
|
||||||
|
tags: string[];
|
||||||
|
venueList: {
|
||||||
|
description: string;
|
||||||
|
id: string;
|
||||||
|
interval: number;
|
||||||
|
monitorSubVenues: boolean;
|
||||||
|
name: string;
|
||||||
|
retention: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnalyticsClientLifecycleApiResponse = {
|
||||||
|
ack_signal: number;
|
||||||
|
ack_signal_avg: number;
|
||||||
|
active_ms: number;
|
||||||
|
bssid: string;
|
||||||
|
busy_ms: number;
|
||||||
|
channel: number;
|
||||||
|
channel_width: number;
|
||||||
|
connected: number;
|
||||||
|
inactive: number;
|
||||||
|
ipv4: string;
|
||||||
|
ipv6: string;
|
||||||
|
mode: string;
|
||||||
|
noise: number;
|
||||||
|
receive_ms: number;
|
||||||
|
rssi: number;
|
||||||
|
rx_bitrate: number;
|
||||||
|
rx_bytes: number;
|
||||||
|
rx_chwidth: number;
|
||||||
|
rx_duration: number;
|
||||||
|
rx_mcs: number;
|
||||||
|
rx_nss: number;
|
||||||
|
rx_packets: number;
|
||||||
|
rx_vht: boolean;
|
||||||
|
ssid: string;
|
||||||
|
station_id: string;
|
||||||
|
timestamp: number;
|
||||||
|
tx_bitrate: number;
|
||||||
|
tx_bytes: number;
|
||||||
|
tx_chwidth: number;
|
||||||
|
tx_duration: number;
|
||||||
|
tx_mcs: number;
|
||||||
|
tx_nss: number;
|
||||||
|
tx_packets: number;
|
||||||
|
tx_power: number;
|
||||||
|
tx_retries: number;
|
||||||
|
tx_vht: boolean;
|
||||||
|
venue_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnalyticsApData = {
|
||||||
|
collisions: number;
|
||||||
|
multicast: number;
|
||||||
|
rx_bytes: number;
|
||||||
|
rx_bytes_bw: number;
|
||||||
|
rx_bytes_delta: number;
|
||||||
|
rx_dropped: number;
|
||||||
|
rx_dropped_delta: number;
|
||||||
|
rx_dropped_pct: number;
|
||||||
|
rx_errors: number;
|
||||||
|
rx_errors_delta: number;
|
||||||
|
rx_errors_pct: number;
|
||||||
|
rx_packets: number;
|
||||||
|
rx_packets_bw: number;
|
||||||
|
rx_packets_delta: number;
|
||||||
|
tx_bytes: number;
|
||||||
|
tx_bytes_bw: number;
|
||||||
|
tx_bytes_delta: number;
|
||||||
|
tx_dropped: number;
|
||||||
|
tx_dropped_delta: number;
|
||||||
|
tx_dropped_pct: number;
|
||||||
|
tx_errors: number;
|
||||||
|
tx_errors_delta: number;
|
||||||
|
tx_errors_pct: number;
|
||||||
|
tx_packets: number;
|
||||||
|
tx_packets_bw: number;
|
||||||
|
tx_packets_delta: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnalyticsRadioData = {
|
||||||
|
active_ms: number;
|
||||||
|
active_pct: number;
|
||||||
|
band: number;
|
||||||
|
busy_ms: number;
|
||||||
|
busy_pct: number;
|
||||||
|
channel: number;
|
||||||
|
channel_width: number;
|
||||||
|
noise: number;
|
||||||
|
receive_ms: number;
|
||||||
|
receive_pct: number;
|
||||||
|
temperature: number;
|
||||||
|
transmit_ms: number;
|
||||||
|
transmit_pct: number;
|
||||||
|
tx_power: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnalyticsAssociationData = {
|
||||||
|
connected: number;
|
||||||
|
inactive: number;
|
||||||
|
rssi: number;
|
||||||
|
rx_bytes: number;
|
||||||
|
rx_bytes_bw: number;
|
||||||
|
rx_bytes_delta: number;
|
||||||
|
rx_packets: number;
|
||||||
|
rx_packets_bw: number;
|
||||||
|
rx_packets_delta: number;
|
||||||
|
rx_rate: {
|
||||||
|
bitrate: number;
|
||||||
|
chwidth: number;
|
||||||
|
ht: boolean;
|
||||||
|
mcs: number;
|
||||||
|
nss: number;
|
||||||
|
sgi: boolean;
|
||||||
|
};
|
||||||
|
station: string;
|
||||||
|
tx_bytes: number;
|
||||||
|
tx_bytes_bw: number;
|
||||||
|
tx_bytes_delta: number;
|
||||||
|
tx_duration: number;
|
||||||
|
tx_duration_delta: number;
|
||||||
|
tx_duration_pct: number;
|
||||||
|
tx_failed: number;
|
||||||
|
tx_failed_delta: number;
|
||||||
|
tx_failed_pct: number;
|
||||||
|
tx_packets: number;
|
||||||
|
tx_packets_bw: number;
|
||||||
|
tx_packets_delta: number;
|
||||||
|
tx_rate: {
|
||||||
|
bitrate: number;
|
||||||
|
chwidth: number;
|
||||||
|
ht: boolean;
|
||||||
|
mcs: number;
|
||||||
|
nss: number;
|
||||||
|
sgi: boolean;
|
||||||
|
};
|
||||||
|
tx_retries: number;
|
||||||
|
tx_retries_delta: number;
|
||||||
|
tx_retries_pct: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnalyticsSsidData = {
|
||||||
|
associations: AnalyticsAssociationData[];
|
||||||
|
band: 2;
|
||||||
|
bssid: string;
|
||||||
|
channel: number;
|
||||||
|
mode: string;
|
||||||
|
rx_bytes_bw: {
|
||||||
|
avg: number;
|
||||||
|
max: number;
|
||||||
|
min: number;
|
||||||
|
};
|
||||||
|
rx_packets_bw: {
|
||||||
|
avg: number;
|
||||||
|
max: number;
|
||||||
|
min: number;
|
||||||
|
};
|
||||||
|
ssid: string;
|
||||||
|
tx_bytes_bw: {
|
||||||
|
avg: number;
|
||||||
|
max: number;
|
||||||
|
min: number;
|
||||||
|
};
|
||||||
|
tx_duration_pct: {
|
||||||
|
avg: number;
|
||||||
|
max: number;
|
||||||
|
min: number;
|
||||||
|
};
|
||||||
|
tx_failed_pct: {
|
||||||
|
avg: number;
|
||||||
|
max: number;
|
||||||
|
min: number;
|
||||||
|
};
|
||||||
|
tx_packets_bw: {
|
||||||
|
avg: number;
|
||||||
|
max: number;
|
||||||
|
min: number;
|
||||||
|
};
|
||||||
|
tx_retries_pct: {
|
||||||
|
avg: number;
|
||||||
|
max: number;
|
||||||
|
min: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnalyticsTimePointApiResponse = {
|
||||||
|
ap_data: AnalyticsApData;
|
||||||
|
boardId: string;
|
||||||
|
device_info: AnalyticsBoardDevice;
|
||||||
|
id: string;
|
||||||
|
radio_data: AnalyticsRadioData[];
|
||||||
|
serialNumber: string;
|
||||||
|
ssid_data: AnalyticsSsidData[];
|
||||||
|
timestamp: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnalyticsTimePointsApiResponse = {
|
||||||
|
points: AnalyticsTimePointApiResponse[][];
|
||||||
|
};
|
||||||
|
|
||||||
export const useGetAnalyticsBoard = ({ id }: { id?: string }) => {
|
export const useGetAnalyticsBoard = ({ id }: { id?: string }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
return useQuery(['get-board', id], () => axiosAnalytics.get(`board/${id}`).then(({ data }) => data), {
|
|
||||||
enabled: id !== undefined && id !== null && id.length > 0,
|
|
||||||
onError: (e: AxiosError) => {
|
|
||||||
if (!toast.isActive('board-fetching-error'))
|
|
||||||
toast({
|
|
||||||
id: 'board-fetching-error',
|
|
||||||
title: t('common.error'),
|
|
||||||
description: t('crud.error_fetching_obj', {
|
|
||||||
obj: t('analytics.board'),
|
|
||||||
e: e?.response?.data?.ErrorDescription,
|
|
||||||
}),
|
|
||||||
status: 'error',
|
|
||||||
duration: 5000,
|
|
||||||
isClosable: true,
|
|
||||||
position: 'top-right',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useGetAnalyticsBoardDevices = ({ id }: { id: string }) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const toast = useToast();
|
|
||||||
|
|
||||||
return useQuery(
|
return useQuery(
|
||||||
['get-board-devices', id],
|
['get-board', id],
|
||||||
() => axiosAnalytics.get(`board/${id}/devices`).then(({ data }) => data.devices),
|
() => axiosAnalytics.get(`board/${id}`).then(({ data }: { data: AnalyticsBoardApiResponse }) => data),
|
||||||
{
|
{
|
||||||
enabled: id !== undefined && id !== null && id.length > 0,
|
enabled: id !== undefined && id !== null && id.length > 0,
|
||||||
onError: (e: AxiosError) => {
|
onError: (e: AxiosError) => {
|
||||||
if (!toast.isActive('board-fetching-error'))
|
if (e.response?.status !== 404 && !toast.isActive('board-fetching-error'))
|
||||||
toast({
|
toast({
|
||||||
id: 'board-fetching-error',
|
id: 'board-fetching-error',
|
||||||
title: t('common.error'),
|
title: t('common.error'),
|
||||||
@@ -57,24 +271,35 @@ export const useGetAnalyticsBoardDevices = ({ id }: { id: string }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPartialClients = async (venueId: string, offset: number) =>
|
export const useGetAnalyticsBoardDevices = ({ id }: { id?: string }) => {
|
||||||
axiosAnalytics
|
const { t } = useTranslation();
|
||||||
.get(`wifiClientHistory?macsOnly=true&venue=${venueId}&limit=500&offset=${offset}`)
|
const toast = useToast();
|
||||||
.then(({ data }) => data.entries as string[]);
|
|
||||||
|
|
||||||
export const getAllClients = async (venueId: string) => {
|
return useQuery(
|
||||||
const allClients: string[] = [];
|
['get-board-devices', id],
|
||||||
let continueFirmware = true;
|
() =>
|
||||||
let offset = 0;
|
axiosAnalytics
|
||||||
while (continueFirmware) {
|
.get(`board/${id}/devices`)
|
||||||
// eslint-disable-next-line no-await-in-loop
|
.then(({ data }: { data: AnalyticsBoardDevicesApiResponse }) => data.devices),
|
||||||
const newClients = await getPartialClients(venueId, offset);
|
{
|
||||||
if (newClients === null || newClients.length === 0 || newClients.length < 500 || offset >= 50000)
|
enabled: id !== undefined && id !== null && id.length > 0,
|
||||||
continueFirmware = false;
|
onError: (e: AxiosError) => {
|
||||||
allClients.push(...newClients);
|
if (e.response?.status !== 404 && !toast.isActive('board-fetching-error'))
|
||||||
offset += 500;
|
toast({
|
||||||
}
|
id: 'board-fetching-error',
|
||||||
return allClients;
|
title: t('common.error'),
|
||||||
|
description: t('crud.error_fetching_obj', {
|
||||||
|
obj: t('analytics.board'),
|
||||||
|
e: e?.response?.data?.ErrorDescription,
|
||||||
|
}),
|
||||||
|
status: 'error',
|
||||||
|
duration: 5000,
|
||||||
|
isClosable: true,
|
||||||
|
position: 'top-right',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetAnalyticsClients = ({ venueId }: { venueId: string }) => {
|
export const useGetAnalyticsClients = ({ venueId }: { venueId: string }) => {
|
||||||
@@ -83,7 +308,10 @@ export const useGetAnalyticsClients = ({ venueId }: { venueId: string }) => {
|
|||||||
|
|
||||||
return useQuery(
|
return useQuery(
|
||||||
['get-venue-analytics-clients', venueId],
|
['get-venue-analytics-clients', venueId],
|
||||||
() => axiosAnalytics.get(`wifiClientHistory?macsOnly=true&venue=${venueId}`).then(({ data }) => data.entries),
|
() =>
|
||||||
|
axiosAnalytics
|
||||||
|
.get(`wifiClientHistory?macsOnly=true&venue=${venueId}`)
|
||||||
|
.then(({ data }: { data: { entries: string[] } }) => data.entries),
|
||||||
{
|
{
|
||||||
onError: (e: AxiosError) => {
|
onError: (e: AxiosError) => {
|
||||||
if (!toast.isActive('get-venue-analytics-clients-error'))
|
if (!toast.isActive('get-venue-analytics-clients-error'))
|
||||||
@@ -107,12 +335,35 @@ export const useGetAnalyticsClients = ({ venueId }: { venueId: string }) => {
|
|||||||
export const useGetClientLifecycleTableSpecs = () =>
|
export const useGetClientLifecycleTableSpecs = () =>
|
||||||
useQuery(
|
useQuery(
|
||||||
['get-lifecycles-table-spec'],
|
['get-lifecycles-table-spec'],
|
||||||
() => axiosAnalytics.get(`wifiClientHistory/0?orderSpec=true`).then(({ data }) => data.list),
|
() =>
|
||||||
|
axiosAnalytics
|
||||||
|
.get(`wifiClientHistory/0?orderSpec=true`)
|
||||||
|
.then(({ data }: { data: { list: string[] } }) => data.list),
|
||||||
{
|
{
|
||||||
staleTime: Infinity,
|
staleTime: Infinity,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const getPartialClients = async (venueId: string, offset: number) =>
|
||||||
|
axiosAnalytics
|
||||||
|
.get(`wifiClientHistory?macsOnly=true&venue=${venueId}&limit=500&offset=${offset}`)
|
||||||
|
.then(({ data }) => data.entries as string[]);
|
||||||
|
|
||||||
|
export const getAllClients = async (venueId: string) => {
|
||||||
|
const allClients: string[] = [];
|
||||||
|
let continueFirmware = true;
|
||||||
|
let offset = 0;
|
||||||
|
while (continueFirmware) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const newClients = await getPartialClients(venueId, offset);
|
||||||
|
if (newClients === null || newClients.length === 0 || newClients.length < 500 || offset >= 50000)
|
||||||
|
continueFirmware = false;
|
||||||
|
allClients.push(...newClients);
|
||||||
|
offset += 500;
|
||||||
|
}
|
||||||
|
return allClients;
|
||||||
|
};
|
||||||
|
|
||||||
export const useGetClientLifecycleCount = ({
|
export const useGetClientLifecycleCount = ({
|
||||||
venueId,
|
venueId,
|
||||||
mac,
|
mac,
|
||||||
@@ -134,7 +385,7 @@ export const useGetClientLifecycleCount = ({
|
|||||||
() =>
|
() =>
|
||||||
axiosAnalytics
|
axiosAnalytics
|
||||||
.get(`wifiClientHistory/${mac}?venue=${venueId}&countOnly=true&fromDate=${fromDate}&endDate=${endDate}`)
|
.get(`wifiClientHistory/${mac}?venue=${venueId}&countOnly=true&fromDate=${fromDate}&endDate=${endDate}`)
|
||||||
.then(({ data }) => data.count),
|
.then(({ data }: { data: { count: number } }) => data.count),
|
||||||
{
|
{
|
||||||
enabled: mac !== undefined,
|
enabled: mac !== undefined,
|
||||||
onError: (e: AxiosError) => {
|
onError: (e: AxiosError) => {
|
||||||
@@ -190,7 +441,7 @@ export const useGetClientLifecycle = ({
|
|||||||
(pageInfo?.limit ?? 10) * (pageInfo?.index ?? 1)
|
(pageInfo?.limit ?? 10) * (pageInfo?.index ?? 1)
|
||||||
}${sortString}&fromDate=${fromDate}&endDate=${endDate}`,
|
}${sortString}&fromDate=${fromDate}&endDate=${endDate}`,
|
||||||
)
|
)
|
||||||
.then(({ data }) => data.entries),
|
.then(({ data }: { data: { entries: AnalyticsClientLifecycleApiResponse[] } }) => data.entries),
|
||||||
{
|
{
|
||||||
keepPreviousData: true,
|
keepPreviousData: true,
|
||||||
enabled: count !== undefined && pageInfo !== undefined,
|
enabled: count !== undefined && pageInfo !== undefined,
|
||||||
@@ -205,7 +456,7 @@ export const useGetAnalyticsBoardTimepoints = ({
|
|||||||
endTime,
|
endTime,
|
||||||
enabled = true,
|
enabled = true,
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id?: string;
|
||||||
startTime: Date;
|
startTime: Date;
|
||||||
endTime?: Date;
|
endTime?: Date;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
@@ -214,19 +465,21 @@ export const useGetAnalyticsBoardTimepoints = ({
|
|||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
return useQuery(
|
return useQuery(
|
||||||
['get-board-timepoints', id],
|
['get-venue-timepoints', id, startTime.toString(), endTime?.toString()],
|
||||||
() =>
|
() =>
|
||||||
axiosAnalytics
|
axiosAnalytics
|
||||||
.get(
|
.get(
|
||||||
`board/${id}/timepoints?fromDate=${Math.floor(startTime.getTime() / 1000)}${
|
`board/${id}/timepoints?maxRecords=1000&fromDate=${Math.floor(startTime.getTime() / 1000)}${
|
||||||
endTime ? `&endDate=${Math.floor(endTime.getTime() / 1000)}` : ''
|
endTime ? `&endDate=${Math.floor(endTime.getTime() / 1000)}` : ''
|
||||||
}`,
|
}`,
|
||||||
)
|
)
|
||||||
.then(({ data }) => data.points),
|
.then(({ data }: { data: AnalyticsTimePointsApiResponse }) => data.points),
|
||||||
{
|
{
|
||||||
enabled: id !== null && enabled,
|
enabled: id !== undefined && id !== '' && enabled,
|
||||||
|
keepPreviousData: true,
|
||||||
|
staleTime: Infinity,
|
||||||
onError: (e: AxiosError) => {
|
onError: (e: AxiosError) => {
|
||||||
if (!toast.isActive('board-fetching-error'))
|
if (e.response?.status !== 404 && !toast.isActive('board-fetching-error'))
|
||||||
toast({
|
toast({
|
||||||
id: 'board-fetching-error',
|
id: 'board-fetching-error',
|
||||||
title: t('common.error'),
|
title: t('common.error'),
|
||||||
|
|||||||
@@ -1,5 +1,17 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { Box, Center, Flex, Heading, Spacer, Spinner, useDisclosure } from '@chakra-ui/react';
|
import {
|
||||||
|
Alert,
|
||||||
|
AlertDescription,
|
||||||
|
AlertIcon,
|
||||||
|
AlertTitle,
|
||||||
|
Box,
|
||||||
|
Center,
|
||||||
|
Flex,
|
||||||
|
Heading,
|
||||||
|
Spacer,
|
||||||
|
Spinner,
|
||||||
|
useDisclosure,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import VenueAnalyticsHeader from './Header';
|
import VenueAnalyticsHeader from './Header';
|
||||||
@@ -16,7 +28,7 @@ const VenueDashboard = ({ boardId }) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure(false);
|
const { isOpen, onOpen, onClose } = useDisclosure(false);
|
||||||
const [tableOptions, setTableOptions] = useState(null);
|
const [tableOptions, setTableOptions] = useState(null);
|
||||||
const { data: devices, isFetching, refetch } = useGetAnalyticsBoardDevices({ id: boardId });
|
const { data: devices, isFetching, refetch, error } = useGetAnalyticsBoardDevices({ id: boardId });
|
||||||
|
|
||||||
const handleRefreshClick = () => {
|
const handleRefreshClick = () => {
|
||||||
refetch();
|
refetch();
|
||||||
@@ -112,6 +124,21 @@ const VenueDashboard = ({ boardId }) => {
|
|||||||
if (!isOpen) setTableOptions(null);
|
if (!isOpen) setTableOptions(null);
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return (
|
||||||
|
<Center mt={6}>
|
||||||
|
<Alert status="error" w="unset" borderRadius="15px">
|
||||||
|
<AlertIcon />
|
||||||
|
<Box>
|
||||||
|
<AlertTitle>{t('common.error')}</AlertTitle>
|
||||||
|
<AlertDescription>
|
||||||
|
{error.response?.status === 404 ? t('analytics.missing_board') : error.response?.data?.ErrorDescription}
|
||||||
|
</AlertDescription>
|
||||||
|
</Box>
|
||||||
|
</Alert>
|
||||||
|
</Center>
|
||||||
|
);
|
||||||
|
|
||||||
return !devices ? (
|
return !devices ? (
|
||||||
<Center mt={6}>
|
<Center mt={6}>
|
||||||
<Spinner size="xl" />
|
<Spinner size="xl" />
|
||||||
|
|||||||
@@ -1,7 +1,19 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Box, Center, Flex, Spacer, Spinner, useColorModeValue } from '@chakra-ui/react';
|
import {
|
||||||
|
Alert,
|
||||||
|
AlertDescription,
|
||||||
|
AlertIcon,
|
||||||
|
AlertTitle,
|
||||||
|
Box,
|
||||||
|
Center,
|
||||||
|
Flex,
|
||||||
|
Spacer,
|
||||||
|
Spinner,
|
||||||
|
useColorModeValue,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { FullScreen, useFullScreenHandle } from 'react-full-screen';
|
import { FullScreen, useFullScreenHandle } from 'react-full-screen';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import CirclePack from './CirclePack';
|
import CirclePack from './CirclePack';
|
||||||
import ExpandButton from './ExpandButton';
|
import ExpandButton from './ExpandButton';
|
||||||
import CirclePackTimePickers from './TimePickers';
|
import CirclePackTimePickers from './TimePickers';
|
||||||
@@ -17,11 +29,32 @@ const propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const VenueLiveView = ({ boardId, venue }) => {
|
const VenueLiveView = ({ boardId, venue }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const handle = useFullScreenHandle();
|
const handle = useFullScreenHandle();
|
||||||
const color = useColorModeValue('gray.50', 'gray.800');
|
const color = useColorModeValue('gray.50', 'gray.800');
|
||||||
const [startTime, setStartTime] = useState(getHoursAgo(1));
|
const [startTime, setStartTime] = useState(getHoursAgo(1));
|
||||||
const [endTime, setEndTime] = useState(new Date());
|
const [endTime, setEndTime] = useState(new Date());
|
||||||
const { data: timepoints, isFetching, refetch } = useGetAnalyticsBoardTimepoints({ id: boardId, startTime, endTime });
|
const {
|
||||||
|
data: timepoints,
|
||||||
|
isFetching,
|
||||||
|
refetch,
|
||||||
|
error,
|
||||||
|
} = useGetAnalyticsBoardTimepoints({ id: boardId, startTime, endTime });
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return (
|
||||||
|
<Center mt={6}>
|
||||||
|
<Alert status="error" w="unset" borderRadius="15px">
|
||||||
|
<AlertIcon />
|
||||||
|
<Box>
|
||||||
|
<AlertTitle>{t('common.error')}</AlertTitle>
|
||||||
|
<AlertDescription>
|
||||||
|
{error.response?.status === 404 ? t('analytics.missing_board') : error.response?.data?.ErrorDescription}
|
||||||
|
</AlertDescription>
|
||||||
|
</Box>
|
||||||
|
</Alert>
|
||||||
|
</Center>
|
||||||
|
);
|
||||||
|
|
||||||
return !timepoints ? (
|
return !timepoints ? (
|
||||||
<Center mt={6}>
|
<Center mt={6}>
|
||||||
|
|||||||
Reference in New Issue
Block a user