mirror of
https://github.com/Telecominfraproject/wlan-cloud-owprov-ui.git
synced 2025-10-29 17:52:25 +00:00
[WIFI-12286] Add support for new venue upgrade API
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.9.0(8)",
|
||||
"version": "2.9.0(10)",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wlan-cloud-owprov-ui",
|
||||
"version": "2.9.0(8)",
|
||||
"version": "2.9.0(10)",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@chakra-ui/icons": "^2.0.11",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wlan-cloud-owprov-ui",
|
||||
"version": "2.9.0(8)",
|
||||
"version": "2.9.0(10)",
|
||||
"description": "",
|
||||
"main": "index.tsx",
|
||||
"scripts": {
|
||||
|
||||
@@ -630,6 +630,8 @@
|
||||
"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",
|
||||
"restricted_overriden": "Dies ist ein eingeschränktes Gerät, aber es befindet sich im Entwicklungsmodus. Alle Einschränkungen werden derzeit ignoriert",
|
||||
"restrictions_overriden_title": "Dev-Modus",
|
||||
"sanity": "Gesundheit",
|
||||
"start_import": "Geräteimport starten",
|
||||
"test_batch": "Testen Sie Importdaten",
|
||||
@@ -683,6 +685,13 @@
|
||||
"update_success": "Entität aktualisiert!",
|
||||
"venues_under_root": "Veranstaltungsorte können nicht direkt unter der Root-Entität erstellt werden"
|
||||
},
|
||||
"firmware": {
|
||||
"db_update_warning": "Dieser Vorgang wird täglich automatisch durchgeführt, ohne dass dieses manuelle Update verwendet werden muss. Die Aktualisierung dieser Datenbank kann bis zu 25 Minuten dauern",
|
||||
"last_db_update_modal": "Firmware-Datenbank",
|
||||
"last_db_update_title": "Datenbank",
|
||||
"start_db_update": "Datenbankaktualisierung starten",
|
||||
"started_db_update": "Datenbankaktualisierung gestartet, dieser Vorgang sollte bis zu 25 Minuten dauern"
|
||||
},
|
||||
"footer": {
|
||||
"powered_by": "Unterstützt von",
|
||||
"version": "Ausführung"
|
||||
@@ -1123,9 +1132,10 @@
|
||||
"title": "Veranstaltungsorte",
|
||||
"update_all_devices": "Alle Gerätekonfigurationen aktualisieren",
|
||||
"update_success": "Veranstaltungsort aktualisiert!",
|
||||
"upgrade_all_devices": "Aktualisieren Sie alle Geräte auf die neueste Firmware",
|
||||
"upgrade_all_devices": "Aktualisieren Sie die Firmware aller Geräte",
|
||||
"upgrade_all_devices_error": "Fehler beim Aktualisieren von Geräten: {{e}}",
|
||||
"upgrade_all_devices_success": "Upgrade von Geräten erfolgreich gestartet!",
|
||||
"upgrade_options_available": "Hier sind alle verfügbaren Revisionen, bitte wählen Sie diejenige aus, auf die ALLE Geräte dieses Veranstaltungsortes aktualisiert werden sollen",
|
||||
"use_existing": "Benutze existierendes",
|
||||
"use_existing_contacts": "Verwenden Sie vorhandene Kontakte",
|
||||
"use_this_contact": "Verwenden Sie diesen Kontakt"
|
||||
|
||||
@@ -630,6 +630,8 @@
|
||||
"one": "Device",
|
||||
"reassign_already_owned": "Reassign devices which already exist and are owned by another entity/venue/subscriber?",
|
||||
"restricted": "Restricted",
|
||||
"restricted_overriden": "This is a restricted device, but it is in development mode. All restrictions are currently ignored",
|
||||
"restrictions_overriden_title": "Dev Mode",
|
||||
"sanity": "Sanity",
|
||||
"start_import": "Start Device Importation",
|
||||
"test_batch": "Test Import Data",
|
||||
@@ -683,6 +685,13 @@
|
||||
"update_success": "Entity updated!",
|
||||
"venues_under_root": "Venues cannot be created directly under the root entity"
|
||||
},
|
||||
"firmware": {
|
||||
"db_update_warning": "This operation is done daily automatically without need to use this manual update. Updating this database can take up to 25 minutes",
|
||||
"last_db_update_modal": "Firmware Database",
|
||||
"last_db_update_title": "Database",
|
||||
"start_db_update": "Start Database Update",
|
||||
"started_db_update": "Started database update, this operation should take up to 25 minutes to complete"
|
||||
},
|
||||
"footer": {
|
||||
"powered_by": "Powered By",
|
||||
"version": "Version"
|
||||
@@ -1123,9 +1132,10 @@
|
||||
"title": "Venues",
|
||||
"update_all_devices": "Update All Device Configurations",
|
||||
"update_success": "Venue updated!",
|
||||
"upgrade_all_devices": "Upgrade All Devices to Latest Firmware",
|
||||
"upgrade_all_devices": "Upgrade All Devices Firmware",
|
||||
"upgrade_all_devices_error": "Error upgrading devices: {{e}}",
|
||||
"upgrade_all_devices_success": "Successfully started upgrading devices!",
|
||||
"upgrade_options_available": "Here are all available revisions, please select the one you want ALL of this venue's devices to be upgrade to",
|
||||
"use_existing": "Use Existing",
|
||||
"use_existing_contacts": "Use Existing Contacts",
|
||||
"use_this_contact": "Use this contact"
|
||||
|
||||
@@ -630,6 +630,8 @@
|
||||
"one": "Dispositivo",
|
||||
"reassign_already_owned": "¿Reasignar dispositivos que ya existen y son propiedad de otra entidad/lugar/suscriptor?",
|
||||
"restricted": "Restringido",
|
||||
"restricted_overriden": "Este es un dispositivo restringido, pero está en modo de desarrollo. Actualmente se ignoran todas las restricciones.",
|
||||
"restrictions_overriden_title": "MODO DE DESARROLLO",
|
||||
"sanity": "Cordura",
|
||||
"start_import": "Iniciar la importación de dispositivos",
|
||||
"test_batch": "Datos de importación de prueba",
|
||||
@@ -683,6 +685,13 @@
|
||||
"update_success": "¡Entidad actualizada!",
|
||||
"venues_under_root": "Los lugares no se pueden crear directamente bajo la entidad raíz"
|
||||
},
|
||||
"firmware": {
|
||||
"db_update_warning": "Esta operación se realiza automáticamente todos los días de forma automática sin necesidad de utilizar esta actualización manual. La actualización de esta base de datos puede tardar hasta 25 minutos",
|
||||
"last_db_update_modal": "Base de datos de firmware",
|
||||
"last_db_update_title": "Base de datos",
|
||||
"start_db_update": "Iniciar actualización de la base de datos",
|
||||
"started_db_update": "Actualización de la base de datos iniciada, esta operación debería tardar hasta 25 minutos en completarse"
|
||||
},
|
||||
"footer": {
|
||||
"powered_by": "energizado por",
|
||||
"version": "Versión"
|
||||
@@ -1123,9 +1132,10 @@
|
||||
"title": "Sedes",
|
||||
"update_all_devices": "Actualizar todas las configuraciones de dispositivos",
|
||||
"update_success": "Lugar actualizado!",
|
||||
"upgrade_all_devices": "Actualice todos los dispositivos al firmware más reciente",
|
||||
"upgrade_all_devices": "Actualizar el firmware de todos los dispositivos",
|
||||
"upgrade_all_devices_error": "Error al actualizar dispositivos: {{e}}",
|
||||
"upgrade_all_devices_success": "¡Comenzó con éxito la actualización de dispositivos!",
|
||||
"upgrade_options_available": "Aquí están todas las revisiones disponibles, seleccione la que desea que TODOS los dispositivos de este lugar se actualicen",
|
||||
"use_existing": "Utilizar existente",
|
||||
"use_existing_contacts": "Usar contactos existentes",
|
||||
"use_this_contact": "Usa este contacto"
|
||||
|
||||
@@ -630,6 +630,8 @@
|
||||
"one": "Dispositif",
|
||||
"reassign_already_owned": "Réattribuer des appareils qui existent déjà et qui appartiennent à une autre entité/salle/abonné ?",
|
||||
"restricted": "Limité",
|
||||
"restricted_overriden": "Il s'agit d'un appareil restreint, mais il est en mode développement. Toutes les restrictions sont actuellement ignorées",
|
||||
"restrictions_overriden_title": "Mode développement",
|
||||
"sanity": "Santé mentale",
|
||||
"start_import": "Démarrer l'importation de l'appareil",
|
||||
"test_batch": "Tester les données d'importation",
|
||||
@@ -683,6 +685,13 @@
|
||||
"update_success": "Entité mise à jour !",
|
||||
"venues_under_root": "Les lieux ne peuvent pas être créés directement sous l'entité racine"
|
||||
},
|
||||
"firmware": {
|
||||
"db_update_warning": "Cette opération se fait automatiquement quotidiennement sans avoir besoin d'utiliser cette mise à jour manuelle. La mise à jour de cette base de données peut prendre jusqu'à 25 minutes",
|
||||
"last_db_update_modal": "Base de données du micrologiciel",
|
||||
"last_db_update_title": "Base de données",
|
||||
"start_db_update": "Démarrer la mise à jour de la base de données",
|
||||
"started_db_update": "Mise à jour de la base de données démarrée, cette opération devrait prendre jusqu'à 25 minutes"
|
||||
},
|
||||
"footer": {
|
||||
"powered_by": "Alimenté par",
|
||||
"version": "Version"
|
||||
@@ -1123,9 +1132,10 @@
|
||||
"title": "Les lieux",
|
||||
"update_all_devices": "Mettre à jour toutes les configurations de périphérique",
|
||||
"update_success": "Lieu mis à jour !",
|
||||
"upgrade_all_devices": "Mettre à niveau tous les appareils vers le dernier micrologiciel",
|
||||
"upgrade_all_devices": "Mettre à niveau le micrologiciel de tous les appareils",
|
||||
"upgrade_all_devices_error": "Erreur lors de la mise à jour des appareils : {{e}}",
|
||||
"upgrade_all_devices_success": "La mise à niveau des appareils a démarré avec succès !",
|
||||
"upgrade_options_available": "Voici toutes les révisions disponibles, veuillez sélectionner celle vers laquelle vous souhaitez que TOUS les appareils de ce lieu soient mis à niveau",
|
||||
"use_existing": "Utiliser l'existant",
|
||||
"use_existing_contacts": "Utiliser les contacts existants",
|
||||
"use_this_contact": "Utilisez ce contact"
|
||||
|
||||
@@ -630,6 +630,8 @@
|
||||
"one": "Dispositivo",
|
||||
"reassign_already_owned": "Reatribuir dispositivos que já existem e são de propriedade de outra entidade/local/assinante?",
|
||||
"restricted": "Restrito",
|
||||
"restricted_overriden": "Este é um dispositivo restrito, mas está em modo de desenvolvimento. Todas as restrições são atualmente ignoradas",
|
||||
"restrictions_overriden_title": "Modo de desenvolvedor",
|
||||
"sanity": "Sanidade",
|
||||
"start_import": "Iniciar importação de dispositivos",
|
||||
"test_batch": "Dados de importação de teste",
|
||||
@@ -683,6 +685,13 @@
|
||||
"update_success": "Entidade atualizada!",
|
||||
"venues_under_root": "Os locais não podem ser criados diretamente na entidade raiz"
|
||||
},
|
||||
"firmware": {
|
||||
"db_update_warning": "Esta operação é feita automaticamente diariamente sem necessidade de usar esta atualização manual. A atualização deste banco de dados pode levar até 25 minutos",
|
||||
"last_db_update_modal": "banco de dados de firmware",
|
||||
"last_db_update_title": "base de dados",
|
||||
"start_db_update": "Iniciar atualização do banco de dados",
|
||||
"started_db_update": "Atualização do banco de dados iniciada, esta operação deve levar até 25 minutos para ser concluída"
|
||||
},
|
||||
"footer": {
|
||||
"powered_by": "Distribuído por",
|
||||
"version": "Versão"
|
||||
@@ -1123,9 +1132,10 @@
|
||||
"title": "Locais",
|
||||
"update_all_devices": "Atualizar todas as configurações do dispositivo",
|
||||
"update_success": "Local atualizado!",
|
||||
"upgrade_all_devices": "Atualize todos os dispositivos para o firmware mais recente",
|
||||
"upgrade_all_devices": "Atualize o firmware de todos os dispositivos",
|
||||
"upgrade_all_devices_error": "Erro ao atualizar dispositivos: {{e}}",
|
||||
"upgrade_all_devices_success": "Atualização de dispositivos iniciada com sucesso!",
|
||||
"upgrade_options_available": "Aqui estão todas as revisões disponíveis, selecione aquela para a qual você deseja que TODOS os dispositivos deste local sejam atualizados",
|
||||
"use_existing": "Usar existente",
|
||||
"use_existing_contacts": "Usar contatos existentes",
|
||||
"use_this_contact": "Use este contato"
|
||||
|
||||
@@ -1,22 +1,43 @@
|
||||
import { useToast } from '@chakra-ui/react';
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import useDefaultPage from 'hooks/useDefaultPage';
|
||||
import useDefaultPage from '../useDefaultPage';
|
||||
import { AxiosError } from 'models/Axios';
|
||||
import { Venue } from 'models/Venue';
|
||||
import { DeviceRules } from 'models/Basic';
|
||||
import { Note } from 'models/Note';
|
||||
import { axiosProv } from 'utils/axiosInstances';
|
||||
|
||||
export interface VenueApiResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
parent: string;
|
||||
devices: string[];
|
||||
children: string[];
|
||||
contacts: string[];
|
||||
entity: string;
|
||||
boards: string[];
|
||||
created: number;
|
||||
modified: number;
|
||||
configurations: string[];
|
||||
notes: Note[];
|
||||
variables: string[];
|
||||
location: string;
|
||||
sourceIP: string[];
|
||||
deviceRules: DeviceRules;
|
||||
}
|
||||
|
||||
const getVenuesBatch = async (limit: number, offset: number) =>
|
||||
axiosProv
|
||||
.get(`venue?withExtendedInfo=true&offset=${offset}&limit=${limit}`)
|
||||
.then(({ data }) => data.venues as Venue[]);
|
||||
.then(({ data }) => data.venues as VenueApiResponse[]);
|
||||
|
||||
const getAllVenues = async () => {
|
||||
const limit = 500;
|
||||
let offset = 0;
|
||||
let data: Venue[] = [];
|
||||
let lastResponse: Venue[] = [];
|
||||
let data: VenueApiResponse[] = [];
|
||||
let lastResponse: VenueApiResponse[] = [];
|
||||
do {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
lastResponse = await getVenuesBatch(limit, offset);
|
||||
@@ -81,15 +102,16 @@ export const useGetSelectVenues = ({ select }: { select: string[] }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const useGetVenue = ({ id }: { id: string }) => {
|
||||
export const useGetVenue = ({ id }: { id?: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const toast = useToast();
|
||||
const goToDefaultPage = useDefaultPage();
|
||||
|
||||
return useQuery(
|
||||
['get-venue', id],
|
||||
() => axiosProv.get(`venue/${id}?withExtendedInfo=true`).then(({ data }) => data),
|
||||
() => axiosProv.get(`venue/${id}?withExtendedInfo=true`).then(({ data }: { data: VenueApiResponse }) => data),
|
||||
{
|
||||
enabled: id !== undefined && id !== '',
|
||||
onError: (e: AxiosError) => {
|
||||
if (!toast.isActive('venue-fetching-error'))
|
||||
toast({
|
||||
@@ -104,7 +126,7 @@ export const useGetVenue = ({ id }: { id: string }) => {
|
||||
isClosable: true,
|
||||
position: 'top-right',
|
||||
});
|
||||
goToDefaultPage();
|
||||
if (e.response?.data?.ErrorCode === 404) goToDefaultPage();
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -115,10 +137,25 @@ export const useCreateVenue = () =>
|
||||
axiosProv.post(`venue/0${createObjects ? `?createObjects=${JSON.stringify(createObjects)}` : ''}`, params),
|
||||
);
|
||||
|
||||
export const useUpdateVenue = ({ id }: { id: string }) =>
|
||||
useMutation(({ params, createObjects }: { params: unknown; createObjects: unknown }) =>
|
||||
axiosProv.put(`venue/${id}${createObjects ? `?createObjects=${JSON.stringify(createObjects)}` : ''}`, params),
|
||||
export const useUpdateVenue = ({ id }: { id: string }) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
({ params, createObjects }: { params: Partial<VenueApiResponse>; createObjects?: unknown }) =>
|
||||
axiosProv
|
||||
.put(`venue/${id}${createObjects ? `?createObjects=${JSON.stringify(createObjects)}` : ''}`, params)
|
||||
.then((res: { data: VenueApiResponse }) => res),
|
||||
{
|
||||
onSuccess: ({ data }) => {
|
||||
queryClient.invalidateQueries(['get-entity-tree']);
|
||||
queryClient.invalidateQueries(['get-venues']);
|
||||
queryClient.invalidateQueries(['get-all-locations', id]);
|
||||
queryClient.setQueryData(['get-venue', id], data);
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const useUpdateVenueDevices = ({ id }: { id: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const toast = useToast();
|
||||
@@ -185,36 +222,38 @@ export const useRebootVenueDevices = ({ id }: { id: string }) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpgradeVenueDevices = ({ id }: { id: string }) => {
|
||||
export const useUpgradeVenueDevices = () => {
|
||||
const { t } = useTranslation();
|
||||
const toast = useToast();
|
||||
|
||||
return useMutation(() => axiosProv.put(`venue/${id}?upgradeAllDevices=true`, {}), {
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
id: 'venue-upgrade-devices-success',
|
||||
title: t('common.success'),
|
||||
description: t('venues.upgrade_all_devices_success'),
|
||||
status: 'success',
|
||||
duration: 5000,
|
||||
isClosable: true,
|
||||
position: 'top-right',
|
||||
});
|
||||
return useMutation(
|
||||
(data: { id: string; revision: string }) =>
|
||||
axiosProv.put(`venue/${data.id}?upgradeAllDevices=true&revision=${data.revision}`, {}),
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
id: 'venue-upgrade-devices-success',
|
||||
title: t('common.success'),
|
||||
description: t('venues.upgrade_all_devices_success'),
|
||||
status: 'success',
|
||||
duration: 5000,
|
||||
isClosable: true,
|
||||
position: 'top-right',
|
||||
});
|
||||
},
|
||||
onError: (e: AxiosError) => {
|
||||
toast({
|
||||
id: uuid(),
|
||||
title: t('common.error'),
|
||||
description: e?.response?.data?.ErrorDescription,
|
||||
status: 'error',
|
||||
duration: 5000,
|
||||
isClosable: true,
|
||||
position: 'top-right',
|
||||
});
|
||||
},
|
||||
},
|
||||
onError: (e: AxiosError) => {
|
||||
toast({
|
||||
id: uuid(),
|
||||
title: t('common.error'),
|
||||
description: t('crud.upgrade_all_devices_error', {
|
||||
e: e?.response?.data?.ErrorDescription,
|
||||
}),
|
||||
status: 'error',
|
||||
duration: 5000,
|
||||
isClosable: true,
|
||||
position: 'top-right',
|
||||
});
|
||||
},
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
export const useDeleteVenue = () => useMutation((id) => axiosProv.delete(`venue/${id}`));
|
||||
@@ -271,3 +310,21 @@ export const useRemoveVenueContact = ({
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
type Release = {
|
||||
date: number;
|
||||
revision: string;
|
||||
};
|
||||
const getVenueUpgradeAvailableFirmware = (id: string) =>
|
||||
axiosProv.put(`venue/${id}?upgradeAllDevices=true&revisionsAvailable=true`, {}).then(
|
||||
(res: {
|
||||
data: {
|
||||
releases: Release[];
|
||||
releasesCandidates: Release[];
|
||||
developmentReleases: Release[];
|
||||
};
|
||||
}) => res.data,
|
||||
);
|
||||
|
||||
export const useGetVenueUpgradeAvailableFirmware = ({ id }: { id: string }) =>
|
||||
useQuery(['venue', id, 'availableFirmware'], () => getVenueUpgradeAvailableFirmware(id));
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
import React from 'react';
|
||||
import { ChevronDownIcon } from '@chakra-ui/icons';
|
||||
import { Button, Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/react';
|
||||
import { IconButton, Menu, MenuButton, MenuItem, MenuList, Tooltip, useDisclosure } from '@chakra-ui/react';
|
||||
import { Wrench } from 'phosphor-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useRebootVenueDevices, useUpdateVenueDevices, useUpgradeVenueDevices } from 'hooks/Network/Venues';
|
||||
import VenueFirmwareUpgradeModal from './VenueFirmwareUpgradeModal';
|
||||
import { useRebootVenueDevices, useUpdateVenueDevices } from 'hooks/Network/Venues';
|
||||
|
||||
interface Props {
|
||||
type Props = {
|
||||
venueId: string;
|
||||
isDisabled: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
const VenueActions = (
|
||||
{
|
||||
venueId,
|
||||
isDisabled
|
||||
}: Props
|
||||
) => {
|
||||
const VenueActions = ({ venueId, isDisabled }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { isOpen: isUpgradeOpen, onOpen: onOpenUpgrade, onClose: onCloseUpgrade } = useDisclosure();
|
||||
const { mutateAsync: rebootDevices } = useRebootVenueDevices({ id: venueId });
|
||||
const updateDevices = useUpdateVenueDevices({ id: venueId });
|
||||
const upgradeDevices = useUpgradeVenueDevices({ id: venueId });
|
||||
|
||||
const handleUpdateClick = () => {
|
||||
updateDevices.mutateAsync();
|
||||
@@ -28,21 +24,22 @@ const VenueActions = (
|
||||
rebootDevices();
|
||||
};
|
||||
|
||||
const handleUpgradeDevices = () => {
|
||||
upgradeDevices.mutateAsync();
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu>
|
||||
<MenuButton as={Button} rightIcon={<ChevronDownIcon />} ml={2} isDisabled={isDisabled}>
|
||||
{t('common.actions')}
|
||||
</MenuButton>
|
||||
<MenuList>
|
||||
<MenuItem onClick={handleRebootClick}>{t('venues.reboot_all_devices')}</MenuItem>
|
||||
<MenuItem onClick={handleUpdateClick}>{t('venues.update_all_devices')}</MenuItem>
|
||||
<MenuItem onClick={handleUpgradeDevices}>{t('venues.upgrade_all_devices')}</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
<>
|
||||
<Menu>
|
||||
<Tooltip label={t('common.actions')} hasArrow>
|
||||
<MenuButton as={IconButton} icon={<Wrench size={20} />} ml={2} isDisabled={isDisabled}>
|
||||
{t('common.actions')}
|
||||
</MenuButton>
|
||||
</Tooltip>
|
||||
<MenuList>
|
||||
<MenuItem onClick={handleRebootClick}>{t('venues.reboot_all_devices')}</MenuItem>
|
||||
<MenuItem onClick={handleUpdateClick}>{t('venues.update_all_devices')}</MenuItem>
|
||||
<MenuItem onClick={onOpenUpgrade}>{t('venues.upgrade_all_devices')}</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
<VenueFirmwareUpgradeModal isOpen={isUpgradeOpen} onClose={onCloseUpgrade} venueId={venueId} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
165
src/pages/VenuePage/VenueCard/VenueFirmwareUpgradeModal.tsx
Normal file
165
src/pages/VenuePage/VenueCard/VenueFirmwareUpgradeModal.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Alert,
|
||||
AlertDescription,
|
||||
AlertIcon,
|
||||
Box,
|
||||
Button,
|
||||
Center,
|
||||
ListItem,
|
||||
Spinner,
|
||||
Tab,
|
||||
TabList,
|
||||
TabPanel,
|
||||
TabPanels,
|
||||
Tabs,
|
||||
Text,
|
||||
UnorderedList,
|
||||
} from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import FormattedDate from 'components/FormattedDate';
|
||||
import { Modal } from 'components/Modals/Modal';
|
||||
import { useGetVenueUpgradeAvailableFirmware, useUpgradeVenueDevices } from 'hooks/Network/Venues';
|
||||
import { AxiosError } from 'models/Axios';
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
venueId: string;
|
||||
};
|
||||
|
||||
const VenueFirmwareUpgradeModal = ({ isOpen, onClose, venueId }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const getAvailableFirmware = useGetVenueUpgradeAvailableFirmware({ id: venueId });
|
||||
const upgrade = useUpgradeVenueDevices();
|
||||
const [selectedRevision, setSelectedRevision] = React.useState<string>();
|
||||
|
||||
const onRevisionSelect = (revision: string) => () => {
|
||||
setSelectedRevision(revision);
|
||||
};
|
||||
|
||||
const onUpgradeClick = () => {
|
||||
if (selectedRevision) {
|
||||
upgrade.mutateAsync(
|
||||
{ revision: selectedRevision, id: venueId },
|
||||
{
|
||||
onSuccess: () => {
|
||||
setSelectedRevision(undefined);
|
||||
onClose();
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const listItemStyle = (revision: string) => ({
|
||||
cursor: 'pointer',
|
||||
backgroundColor: revision === selectedRevision ? 'gray.200' : 'white',
|
||||
});
|
||||
|
||||
const displayRevision = (release: { date: number; revision: string }) => (
|
||||
<ListItem key={release.revision} onClick={onRevisionSelect(release.revision)} {...listItemStyle(release.revision)}>
|
||||
<FormattedDate date={release.date} />
|
||||
<Text>{release.revision}</Text>
|
||||
</ListItem>
|
||||
);
|
||||
|
||||
const placeholder = React.useMemo(() => {
|
||||
if (getAvailableFirmware.isFetching) {
|
||||
return (
|
||||
<Center my={6}>
|
||||
<Spinner size="xl" />
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
if (getAvailableFirmware.isError) {
|
||||
return (
|
||||
<Center my={6}>
|
||||
<Alert status="error">
|
||||
<AlertIcon />
|
||||
<AlertDescription>
|
||||
{(getAvailableFirmware.error as AxiosError).response?.data?.ErrorDescription}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [getAvailableFirmware]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isOpen) {
|
||||
setSelectedRevision(undefined);
|
||||
getAvailableFirmware.refetch();
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose} title={t('venues.upgrade_all_devices')}>
|
||||
<Box>
|
||||
{placeholder || !getAvailableFirmware.data ? (
|
||||
placeholder
|
||||
) : (
|
||||
<>
|
||||
<Text fontWeight="bold">{t('venues.upgrade_options_available')}</Text>
|
||||
<Center my={2}>
|
||||
<Button
|
||||
colorScheme="yellow"
|
||||
onClick={onUpgradeClick}
|
||||
isDisabled={!selectedRevision}
|
||||
isLoading={upgrade.isLoading}
|
||||
display="block"
|
||||
>
|
||||
<Text>{selectedRevision ? `Upgrade to ` : 'Select a revision to upgrade'}</Text>
|
||||
{selectedRevision ? <Text mt={1}>{selectedRevision}</Text> : null}
|
||||
</Button>
|
||||
</Center>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab>Official Releases</Tab>
|
||||
<Tab>Release Candidates</Tab>
|
||||
<Tab>Dev Releases</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel>
|
||||
<Text fontWeight="bold" textDecor="underline">
|
||||
Official Releases
|
||||
</Text>
|
||||
<UnorderedList>
|
||||
{getAvailableFirmware.data?.releases
|
||||
.sort((a, b) => b.date - a.date)
|
||||
.map((release) => displayRevision(release))}
|
||||
</UnorderedList>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Text fontWeight="bold" textDecor="underline">
|
||||
Release Candidates
|
||||
</Text>
|
||||
<UnorderedList>
|
||||
{getAvailableFirmware.data?.releasesCandidates
|
||||
.sort((a, b) => b.date - a.date)
|
||||
.map((release) => displayRevision(release))}
|
||||
</UnorderedList>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Text fontWeight="bold" textDecor="underline">
|
||||
Dev Releases
|
||||
</Text>
|
||||
<UnorderedList>
|
||||
{getAvailableFirmware.data?.developmentReleases
|
||||
.sort((a, b) => b.date - a.date)
|
||||
.map((release) => displayRevision(release))}
|
||||
</UnorderedList>
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default VenueFirmwareUpgradeModal;
|
||||
Reference in New Issue
Block a user