diff --git a/package-lock.json b/package-lock.json index bee7f94..c3b4914 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ucentral-client", - "version": "2.8.0(46)", + "version": "2.9.0(1)", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ucentral-client", - "version": "2.8.0(46)", + "version": "2.9.0(1)", "license": "ISC", "dependencies": { "@chakra-ui/icons": "^2.0.11", @@ -6642,8 +6642,9 @@ "license": "MIT" }, "node_modules/json5": { - "version": "2.2.1", - "license": "MIT", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -8853,9 +8854,10 @@ } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, - "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -13688,7 +13690,9 @@ "dev": true }, "json5": { - "version": "2.2.1" + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "jsonfile": { "version": "6.1.0", @@ -14981,7 +14985,9 @@ }, "dependencies": { "json5": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" diff --git a/package.json b/package.json index ed7f78d..75bd5e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ucentral-client", - "version": "2.8.0(46)", + "version": "2.9.0(1)", "description": "", "private": true, "main": "index.tsx", diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json index b3f578f..41853e2 100644 --- a/public/locales/de/translation.json +++ b/public/locales/de/translation.json @@ -175,6 +175,7 @@ "other": "Befehle", "override_dfs": "DFS überschreiben", "reboot": "Starten Sie neu", + "reboot_description": "Möchten Sie dieses Gerät neu starten?", "reboot_error": "Fehler beim Senden des Neustartbefehls: {{e}}", "reboot_success": "Neustartbefehl erfolgreich gesendet!", "revision": "Revision", diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index fbdb696..bc57da6 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -175,6 +175,7 @@ "other": "Commands", "override_dfs": "Override DFS", "reboot": "Reboot", + "reboot_description": "Do you want to reboot this device?", "reboot_error": "Error while sending reboot command: {{e}}", "reboot_success": "Successfully sent reboot command!", "revision": "Revision", diff --git a/public/locales/es/translation.json b/public/locales/es/translation.json index 6bd44e7..9e71e24 100644 --- a/public/locales/es/translation.json +++ b/public/locales/es/translation.json @@ -175,6 +175,7 @@ "other": "comandos", "override_dfs": "Anular DFS", "reboot": "Reiniciar", + "reboot_description": "¿Quieres reiniciar este dispositivo?", "reboot_error": "Error al enviar el comando de reinicio: {{e}}", "reboot_success": "¡Comando de reinicio enviado con éxito!", "revision": "revisión", diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json index 05f8928..680b996 100644 --- a/public/locales/fr/translation.json +++ b/public/locales/fr/translation.json @@ -175,6 +175,7 @@ "other": "Les commandes", "override_dfs": "Remplacer DFS", "reboot": "Redémarrer", + "reboot_description": "Voulez-vous redémarrer cet appareil ?", "reboot_error": "Erreur lors de l'envoi de la commande de redémarrage : {{e}}", "reboot_success": "Commande de redémarrage envoyée avec succès !", "revision": "Révision", diff --git a/public/locales/pt/translation.json b/public/locales/pt/translation.json index 2cd79c9..a1d86e3 100644 --- a/public/locales/pt/translation.json +++ b/public/locales/pt/translation.json @@ -175,6 +175,7 @@ "other": "comandos", "override_dfs": "Substituir DFS", "reboot": "Reiniciar", + "reboot_description": "Deseja reiniciar este dispositivo?", "reboot_error": "Erro ao enviar o comando de reinicialização: {{e}}", "reboot_success": "Comando de reinicialização enviado com sucesso!", "revision": "revisão", diff --git a/src/components/Buttons/DeviceActionDropdown/index.tsx b/src/components/Buttons/DeviceActionDropdown/index.tsx index 71cdc0b..f11e94f 100644 --- a/src/components/Buttons/DeviceActionDropdown/index.tsx +++ b/src/components/Buttons/DeviceActionDropdown/index.tsx @@ -1,9 +1,19 @@ import React from 'react'; -import { Button, IconButton, Menu, MenuButton, MenuItem, MenuList, Spinner, Tooltip, useToast } from '@chakra-ui/react'; +import { + Button, + IconButton, + Menu, + MenuButton, + MenuItem, + MenuList, + Portal, + Spinner, + Tooltip, + useToast, +} from '@chakra-ui/react'; import axios from 'axios'; import { Wrench } from 'phosphor-react'; import { useTranslation } from 'react-i18next'; -import RebootMenuItem from './RebootButton'; import { useControllerStore } from 'contexts/ControllerSocketProvider/useStore'; import { useBlinkDevice, useGetDeviceRtty } from 'hooks/Network/Devices'; import { useUpdateDeviceToLatest } from 'hooks/Network/Firmware'; @@ -22,6 +32,7 @@ interface Props { onOpenConfigureModal: (serialNumber: string) => void; onOpenTelemetryModal: (serialNumber: string) => void; onOpenScriptModal: (device: GatewayDevice) => void; + onOpenRebootModal: (serialNumber: string) => void; size?: 'sm' | 'md' | 'lg'; isCompact?: boolean; } @@ -38,6 +49,7 @@ const DeviceActionDropdown = ({ onOpenTelemetryModal, onOpenConfigureModal, onOpenScriptModal, + onOpenRebootModal, size, isCompact, }: Props) => { @@ -145,7 +157,9 @@ const DeviceActionDropdown = ({ }, ); }; + const handleConnectClick = () => getRtty(); + const handleRebootClick = () => onOpenRebootModal(device.serialNumber); return ( @@ -172,22 +186,24 @@ const DeviceActionDropdown = ({ )} - - {t('commands.blink')} - {t('controller.configure.title')} - {t('commands.connect')} - {t('controller.queue.title')} - {t('commands.factory_reset')} - {t('commands.firmware_upgrade')} - - {t('controller.telemetry.title')} - {t('script.one')} - {t('controller.devices.trace')} - - {t('commands.wifiscan')} - + + + {t('commands.blink')} + {t('controller.configure.title')} + {t('commands.connect')} + {t('controller.queue.title')} + {t('commands.factory_reset')} + {t('commands.firmware_upgrade')} + {t('commands.reboot')} + {t('controller.telemetry.title')} + {t('script.one')} + {t('controller.devices.trace')} + + {t('commands.wifiscan')} + + ); }; diff --git a/src/components/Buttons/DeviceActionDropdown/RebootButton.tsx b/src/components/Modals/RebootModal/index.tsx similarity index 58% rename from src/components/Buttons/DeviceActionDropdown/RebootButton.tsx rename to src/components/Modals/RebootModal/index.tsx index 9b7f84d..c329ae6 100644 --- a/src/components/Buttons/DeviceActionDropdown/RebootButton.tsx +++ b/src/components/Modals/RebootModal/index.tsx @@ -1,40 +1,42 @@ import * as React from 'react'; -import { MenuItem, useToast } from '@chakra-ui/react'; +import { Alert, AlertIcon, Box, Button, Center, useToast } from '@chakra-ui/react'; import { useTranslation } from 'react-i18next'; +import { Modal } from '../Modal'; import { useControllerStore } from 'contexts/ControllerSocketProvider/useStore'; import { useRebootDevice } from 'hooks/Network/Devices'; import { useMutationResult } from 'hooks/useMutationResult'; import { AxiosError } from 'models/Axios'; -import { GatewayDevice } from 'models/Device'; -type Props = { - device: GatewayDevice; - refresh: () => void; +export type RebootModalProps = { + serialNumber: string; + modalProps: { + isOpen: boolean; + onClose: () => void; + }; }; -const RebootMenuItem = ({ device, refresh }: Props) => { +export const RebootModal = ({ serialNumber, modalProps }: RebootModalProps) => { const { t } = useTranslation(); const toast = useToast(); const addEventListeners = useControllerStore((state) => state.addEventListeners); - const { mutateAsync: reboot } = useRebootDevice({ serialNumber: device.serialNumber }); + const { mutateAsync: reboot, isLoading } = useRebootDevice({ serialNumber }); const { onSuccess: onRebootSuccess, onError: onRebootError } = useMutationResult({ objName: t('devices.one'), operationType: 'reboot', refresh: () => { - refresh(); addEventListeners([ { - id: `device-connection-${device.serialNumber}`, + id: `device-connection-${serialNumber}`, type: 'DEVICE_CONNECTION', - serialNumber: device.serialNumber, + serialNumber, callback: () => { - const id = `device-connection-notification-${device.serialNumber}`; + const id = `device-connection-notification-${serialNumber}`; if (!toast.isActive(id)) { toast({ id, title: t('common.success'), - description: t('controller.devices.finished_reboot', { serialNumber: device.serialNumber }), + description: t('controller.devices.finished_reboot', { serialNumber }), status: 'success', duration: 5000, isClosable: true, @@ -44,17 +46,17 @@ const RebootMenuItem = ({ device, refresh }: Props) => { }, }, { - id: `device-disconnected-${device.serialNumber}`, + id: `device-disconnected-${serialNumber}`, type: 'DEVICE_DISCONNECTION', - serialNumber: device.serialNumber, + serialNumber, callback: () => { - const id = `device-disconnection-notification-${device.serialNumber}`; + const id = `device-disconnection-notification-${serialNumber}`; if (!toast.isActive(id)) { toast({ id, title: t('common.success'), - description: t('controller.devices.started_reboot', { serialNumber: device.serialNumber }), + description: t('controller.devices.started_reboot', { serialNumber }), status: 'success', duration: 5000, isClosable: true, @@ -66,17 +68,39 @@ const RebootMenuItem = ({ device, refresh }: Props) => { ]); }, }); + const handleRebootClick = () => reboot(undefined, { onSuccess: () => { onRebootSuccess(); + modalProps.onClose(); }, onError: (e) => { onRebootError(e as AxiosError); }, }); - return {t('commands.reboot')}; + return ( + + {t('commands.reboot')} + + } + options={{ + modalSize: 'sm', + }} + > + +
+ + + {t('commands.reboot_description')} + +
+
+
+ ); }; - -export default RebootMenuItem; diff --git a/src/pages/Device/Wrapper.tsx b/src/pages/Device/Wrapper.tsx index 25fcd17..ac74d3a 100644 --- a/src/pages/Device/Wrapper.tsx +++ b/src/pages/Device/Wrapper.tsx @@ -33,6 +33,7 @@ import { ConfigureModal } from 'components/Modals/ConfigureModal'; import { EventQueueModal } from 'components/Modals/EventQueueModal'; import FactoryResetModal from 'components/Modals/FactoryResetModal'; import { FirmwareUpgradeModal } from 'components/Modals/FirmwareUpgradeModal'; +import { RebootModal } from 'components/Modals/RebootModal'; import { useScriptModal } from 'components/Modals/ScriptModal/useScriptModal'; import { TelemetryModal } from 'components/Modals/TelemetryModal'; import { TraceModal } from 'components/Modals/TraceModal'; @@ -56,6 +57,7 @@ const DevicePageWrapper = ({ serialNumber }: Props) => { const upgradeModalProps = useDisclosure(); const telemetryModalProps = useDisclosure(); const traceModalProps = useDisclosure(); + const rebootModalProps = useDisclosure(); const scriptModal = useScriptModal(); const connectedTag = React.useMemo(() => { if (!getStatus.data) return null; @@ -142,6 +144,7 @@ const DevicePageWrapper = ({ serialNumber }: Props) => { onOpenConfigureModal={configureModalProps.onOpen} onOpenTelemetryModal={telemetryModalProps.onOpen} onOpenScriptModal={scriptModal.openModal} + onOpenRebootModal={rebootModalProps.onOpen} size="md" isCompact /> @@ -194,6 +197,7 @@ const DevicePageWrapper = ({ serialNumber }: Props) => { onOpenEventQueue={eventQueueProps.onOpen} onOpenConfigureModal={configureModalProps.onOpen} onOpenTelemetryModal={telemetryModalProps.onOpen} + onOpenRebootModal={rebootModalProps.onOpen} onOpenScriptModal={scriptModal.openModal} size="md" /> @@ -217,6 +221,7 @@ const DevicePageWrapper = ({ serialNumber }: Props) => { + {scriptModal.modal} void; onOpenTelemetryModal: (serialNumber: string) => void; onOpenScriptModal: (device: GatewayDevice) => void; + onOpenRebootModal: (serialNumber: string) => void; } const Actions: React.FC = ({ @@ -47,6 +48,7 @@ const Actions: React.FC = ({ onOpenConfigureModal, onOpenTelemetryModal, onOpenScriptModal, + onOpenRebootModal, }) => { const { t } = useTranslation(); const { isOpen, onOpen, onClose } = useDisclosure(); @@ -102,6 +104,7 @@ const Actions: React.FC = ({ onOpenConfigureModal={onOpenConfigureModal} onOpenTelemetryModal={onOpenTelemetryModal} onOpenScriptModal={onOpenScriptModal} + onOpenRebootModal={onOpenRebootModal} /> diff --git a/src/pages/Devices/ListCard/index.tsx b/src/pages/Devices/ListCard/index.tsx index 989161e..f37bb94 100644 --- a/src/pages/Devices/ListCard/index.tsx +++ b/src/pages/Devices/ListCard/index.tsx @@ -20,6 +20,7 @@ import { ConfigureModal } from 'components/Modals/ConfigureModal'; import { EventQueueModal } from 'components/Modals/EventQueueModal'; import FactoryResetModal from 'components/Modals/FactoryResetModal'; import { FirmwareUpgradeModal } from 'components/Modals/FirmwareUpgradeModal'; +import { RebootModal } from 'components/Modals/RebootModal'; import { useScriptModal } from 'components/Modals/ScriptModal/useScriptModal'; import { TelemetryModal } from 'components/Modals/TelemetryModal'; import { TraceModal } from 'components/Modals/TraceModal'; @@ -58,6 +59,7 @@ const DeviceListCard = () => { const eventQueueProps = useDisclosure(); const telemetryModalProps = useDisclosure(); const configureModalProps = useDisclosure(); + const rebootModalProps = useDisclosure(); const scriptModal = useScriptModal(); const getCount = useGetDeviceCount({ enabled: true }); const getDevices = useGetDevices({ @@ -96,6 +98,10 @@ const DeviceListCard = () => { setSerialNumber(serial); configureModalProps.onOpen(); }; + const onOpenReboot = (serial: string) => { + setSerialNumber(serial); + rebootModalProps.onOpen(); + }; const badgeCell = React.useCallback( (device: DeviceWithStatus) => ( @@ -210,6 +216,7 @@ const DeviceListCard = () => { onOpenConfigureModal={onOpenConfigure} onOpenTelemetryModal={onOpenTelemetry} onOpenScriptModal={scriptModal.openModal} + onOpenRebootModal={onOpenReboot} /> ), [], @@ -410,6 +417,7 @@ const DeviceListCard = () => { + {scriptModal.modal} );