mirror of
https://github.com/Telecominfraproject/wlan-cloud-owprov-ui.git
synced 2025-10-29 17:52:25 +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",
|
||||
"version": "2.8.0(13)",
|
||||
"version": "2.8.0(17)",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wlan-cloud-owprov-ui",
|
||||
"version": "2.8.0(13)",
|
||||
"version": "2.8.0(17)",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@chakra-ui/icons": "^2.0.11",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wlan-cloud-owprov-ui",
|
||||
"version": "2.8.0(13)",
|
||||
"version": "2.8.0(17)",
|
||||
"description": "",
|
||||
"main": "index.tsx",
|
||||
"scripts": {
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
"live_view_help": "Hilfe zur Live-Ansicht",
|
||||
"memory": "Erinnerung",
|
||||
"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",
|
||||
"noise": "Lärm",
|
||||
"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",
|
||||
"invalid_serial_number": "Ungültige Seriennummer (muss 12 HEX-Zeichen lang sein)",
|
||||
"new_devices": "Neue Geräte",
|
||||
"no_model_image": "Kein Modellbild gefunden",
|
||||
"not_connected": "Nicht verbunden",
|
||||
"not_found_gateway": "Fehler: Gerät hat sich noch nicht mit dem Gateway verbunden",
|
||||
"notifications": "Gerätebenachrichtigungen",
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
"live_view_help": "Live View Help",
|
||||
"memory": "Memory",
|
||||
"memory_used": "Memory Used",
|
||||
"missing_board": "Analytics monitoring on this venue is no longer active, please restart monitoring using the top menu",
|
||||
"mode": "Mode",
|
||||
"noise": "Noise",
|
||||
"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",
|
||||
"invalid_serial_number": "Invalid Serial Number (needs to be 12 HEX chars)",
|
||||
"new_devices": "new devices",
|
||||
"no_model_image": "No Model Image Found",
|
||||
"not_connected": "Not Connected",
|
||||
"not_found_gateway": "Error: device has not yet connected to the controller",
|
||||
"notifications": "Device Notifications",
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
"live_view_help": "Ayuda de visualización en vivo",
|
||||
"memory": "Memoria",
|
||||
"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",
|
||||
"noise": "Ruido",
|
||||
"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",
|
||||
"invalid_serial_number": "Número de serie no válido (debe tener 12 caracteres HEX)",
|
||||
"new_devices": "Nuevos dispositivos",
|
||||
"no_model_image": "No se encontró ninguna imagen de modelo",
|
||||
"not_connected": "No conectado",
|
||||
"not_found_gateway": "Error: el dispositivo aún no se ha conectado a la puerta de enlace",
|
||||
"notifications": "notificaciones de dispositivos",
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
"live_view_help": "Aide sur l'affichage en direct",
|
||||
"memory": "mémoire",
|
||||
"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",
|
||||
"noise": "Bruit",
|
||||
"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",
|
||||
"invalid_serial_number": "Numéro de série non valide (doit être composé de 12 caractères HEX)",
|
||||
"new_devices": "nouveaux appareils",
|
||||
"no_model_image": "Aucune image de modèle trouvée",
|
||||
"not_connected": "Pas connecté",
|
||||
"not_found_gateway": "Erreur : l'appareil n'est pas encore connecté à la passerelle",
|
||||
"notifications": "notifications de l'appareil",
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
"live_view_help": "Ajuda da visualização ao vivo",
|
||||
"memory": "Memória",
|
||||
"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",
|
||||
"noise": "Barulho",
|
||||
"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",
|
||||
"invalid_serial_number": "Número de série inválido (precisa ter 12 caracteres HEX)",
|
||||
"new_devices": "novos dispositivos",
|
||||
"no_model_image": "Nenhuma imagem de modelo encontrada",
|
||||
"not_connected": "Não conectado",
|
||||
"not_found_gateway": "Erro: o dispositivo ainda não se conectou ao gateway",
|
||||
"notifications": "Notificações do dispositivo",
|
||||
|
||||
@@ -1,45 +1,259 @@
|
||||
import { useToast } from '@chakra-ui/react';
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { AxiosError } from 'axios';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AxiosError } from 'models/Axios';
|
||||
import { Note } from 'models/Note';
|
||||
import { PageInfo, SortInfo } from 'models/Table';
|
||||
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 }) => {
|
||||
const { t } = useTranslation();
|
||||
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(
|
||||
['get-board-devices', id],
|
||||
() => axiosAnalytics.get(`board/${id}/devices`).then(({ data }) => data.devices),
|
||||
['get-board', id],
|
||||
() => axiosAnalytics.get(`board/${id}`).then(({ data }: { data: AnalyticsBoardApiResponse }) => data),
|
||||
{
|
||||
enabled: id !== undefined && id !== null && id.length > 0,
|
||||
onError: (e: AxiosError) => {
|
||||
if (!toast.isActive('board-fetching-error'))
|
||||
if (e.response?.status !== 404 && !toast.isActive('board-fetching-error'))
|
||||
toast({
|
||||
id: 'board-fetching-error',
|
||||
title: t('common.error'),
|
||||
@@ -57,24 +271,35 @@ export const useGetAnalyticsBoardDevices = ({ id }: { id: string }) => {
|
||||
);
|
||||
};
|
||||
|
||||
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 useGetAnalyticsBoardDevices = ({ id }: { id?: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const toast = useToast();
|
||||
|
||||
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;
|
||||
return useQuery(
|
||||
['get-board-devices', id],
|
||||
() =>
|
||||
axiosAnalytics
|
||||
.get(`board/${id}/devices`)
|
||||
.then(({ data }: { data: AnalyticsBoardDevicesApiResponse }) => data.devices),
|
||||
{
|
||||
enabled: id !== undefined && id !== null && id.length > 0,
|
||||
onError: (e: AxiosError) => {
|
||||
if (e.response?.status !== 404 && !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 useGetAnalyticsClients = ({ venueId }: { venueId: string }) => {
|
||||
@@ -83,7 +308,10 @@ export const useGetAnalyticsClients = ({ venueId }: { venueId: string }) => {
|
||||
|
||||
return useQuery(
|
||||
['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) => {
|
||||
if (!toast.isActive('get-venue-analytics-clients-error'))
|
||||
@@ -107,12 +335,35 @@ export const useGetAnalyticsClients = ({ venueId }: { venueId: string }) => {
|
||||
export const useGetClientLifecycleTableSpecs = () =>
|
||||
useQuery(
|
||||
['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,
|
||||
},
|
||||
);
|
||||
|
||||
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 = ({
|
||||
venueId,
|
||||
mac,
|
||||
@@ -134,7 +385,7 @@ export const useGetClientLifecycleCount = ({
|
||||
() =>
|
||||
axiosAnalytics
|
||||
.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,
|
||||
onError: (e: AxiosError) => {
|
||||
@@ -190,7 +441,7 @@ export const useGetClientLifecycle = ({
|
||||
(pageInfo?.limit ?? 10) * (pageInfo?.index ?? 1)
|
||||
}${sortString}&fromDate=${fromDate}&endDate=${endDate}`,
|
||||
)
|
||||
.then(({ data }) => data.entries),
|
||||
.then(({ data }: { data: { entries: AnalyticsClientLifecycleApiResponse[] } }) => data.entries),
|
||||
{
|
||||
keepPreviousData: true,
|
||||
enabled: count !== undefined && pageInfo !== undefined,
|
||||
@@ -205,7 +456,7 @@ export const useGetAnalyticsBoardTimepoints = ({
|
||||
endTime,
|
||||
enabled = true,
|
||||
}: {
|
||||
id: string;
|
||||
id?: string;
|
||||
startTime: Date;
|
||||
endTime?: Date;
|
||||
enabled?: boolean;
|
||||
@@ -214,19 +465,21 @@ export const useGetAnalyticsBoardTimepoints = ({
|
||||
const toast = useToast();
|
||||
|
||||
return useQuery(
|
||||
['get-board-timepoints', id],
|
||||
['get-venue-timepoints', id, startTime.toString(), endTime?.toString()],
|
||||
() =>
|
||||
axiosAnalytics
|
||||
.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)}` : ''
|
||||
}`,
|
||||
)
|
||||
.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) => {
|
||||
if (!toast.isActive('board-fetching-error'))
|
||||
if (e.response?.status !== 404 && !toast.isActive('board-fetching-error'))
|
||||
toast({
|
||||
id: 'board-fetching-error',
|
||||
title: t('common.error'),
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
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 { useTranslation } from 'react-i18next';
|
||||
import VenueAnalyticsHeader from './Header';
|
||||
@@ -16,7 +28,7 @@ const VenueDashboard = ({ boardId }) => {
|
||||
const { t } = useTranslation();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure(false);
|
||||
const [tableOptions, setTableOptions] = useState(null);
|
||||
const { data: devices, isFetching, refetch } = useGetAnalyticsBoardDevices({ id: boardId });
|
||||
const { data: devices, isFetching, refetch, error } = useGetAnalyticsBoardDevices({ id: boardId });
|
||||
|
||||
const handleRefreshClick = () => {
|
||||
refetch();
|
||||
@@ -112,6 +124,21 @@ const VenueDashboard = ({ boardId }) => {
|
||||
if (!isOpen) setTableOptions(null);
|
||||
}, [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 ? (
|
||||
<Center mt={6}>
|
||||
<Spinner size="xl" />
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
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 { FullScreen, useFullScreenHandle } from 'react-full-screen';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import CirclePack from './CirclePack';
|
||||
import ExpandButton from './ExpandButton';
|
||||
import CirclePackTimePickers from './TimePickers';
|
||||
@@ -17,11 +29,32 @@ const propTypes = {
|
||||
};
|
||||
|
||||
const VenueLiveView = ({ boardId, venue }) => {
|
||||
const { t } = useTranslation();
|
||||
const handle = useFullScreenHandle();
|
||||
const color = useColorModeValue('gray.50', 'gray.800');
|
||||
const [startTime, setStartTime] = useState(getHoursAgo(1));
|
||||
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 ? (
|
||||
<Center mt={6}>
|
||||
|
||||
Reference in New Issue
Block a user