mirror of
				https://github.com/optim-enterprises-bv/OptimCloud-gw-ui.git
				synced 2025-11-04 04:07:49 +00:00 
			
		
		
		
	Merge pull request #195 from stephb9959/main
[WIFI-12948] Fixed view configuration modal cache
This commit is contained in:
		
							
								
								
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,12 +1,12 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "ucentral-client",
 | 
					  "name": "ucentral-client",
 | 
				
			||||||
  "version": "2.11.0(7)",
 | 
					  "version": "2.11.0(11)",
 | 
				
			||||||
  "lockfileVersion": 3,
 | 
					  "lockfileVersion": 3,
 | 
				
			||||||
  "requires": true,
 | 
					  "requires": true,
 | 
				
			||||||
  "packages": {
 | 
					  "packages": {
 | 
				
			||||||
    "": {
 | 
					    "": {
 | 
				
			||||||
      "name": "ucentral-client",
 | 
					      "name": "ucentral-client",
 | 
				
			||||||
      "version": "2.11.0(7)",
 | 
					      "version": "2.11.0(11)",
 | 
				
			||||||
      "license": "ISC",
 | 
					      "license": "ISC",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@chakra-ui/anatomy": "^2.1.1",
 | 
					        "@chakra-ui/anatomy": "^2.1.1",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "ucentral-client",
 | 
					  "name": "ucentral-client",
 | 
				
			||||||
  "version": "2.11.0(7)",
 | 
					  "version": "2.11.0(11)",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "private": true,
 | 
					  "private": true,
 | 
				
			||||||
  "main": "index.tsx",
 | 
					  "main": "index.tsx",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ export type ConfigureModalProps = {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps) => {
 | 
					const _ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps) => {
 | 
				
			||||||
  const { t } = useTranslation();
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
  const toast = useToast();
 | 
					  const toast = useToast();
 | 
				
			||||||
  const configure = useConfigureDevice({ serialNumber });
 | 
					  const configure = useConfigureDevice({ serialNumber });
 | 
				
			||||||
@@ -45,6 +45,7 @@ export const ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps
 | 
				
			|||||||
  const onImportConfiguration = () => {
 | 
					  const onImportConfiguration = () => {
 | 
				
			||||||
    setNewConfig(getDevice.data?.configuration ? JSON.stringify(getDevice.data.configuration, null, 4) : '');
 | 
					    setNewConfig(getDevice.data?.configuration ? JSON.stringify(getDevice.data.configuration, null, 4) : '');
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const isValid = React.useMemo(() => {
 | 
					  const isValid = React.useMemo(() => {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      JSON.parse(newConfig);
 | 
					      JSON.parse(newConfig);
 | 
				
			||||||
@@ -71,9 +72,19 @@ export const ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps
 | 
				
			|||||||
          modalProps.onClose();
 | 
					          modalProps.onClose();
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    } catch (e) {}
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      // do nothing
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  React.useEffect(() => {
 | 
				
			||||||
 | 
					    if (modalProps.isOpen) {
 | 
				
			||||||
 | 
					      getDevice.refetch();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      setNewConfig('');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [modalProps.isOpen]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Modal
 | 
					    <Modal
 | 
				
			||||||
      {...modalProps}
 | 
					      {...modalProps}
 | 
				
			||||||
@@ -124,3 +135,5 @@ export const ConfigureModal = ({ serialNumber, modalProps }: ConfigureModalProps
 | 
				
			|||||||
    </Modal>
 | 
					    </Modal>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ConfigureModal = React.memo(_ConfigureModal);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -187,6 +187,8 @@ export const useConfigureDevice = ({ serialNumber }: { serialNumber: string }) =
 | 
				
			|||||||
  return useMutation(configureDevice(serialNumber), {
 | 
					  return useMutation(configureDevice(serialNumber), {
 | 
				
			||||||
    onSuccess: () => {
 | 
					    onSuccess: () => {
 | 
				
			||||||
      queryClient.invalidateQueries(['commands', serialNumber]);
 | 
					      queryClient.invalidateQueries(['commands', serialNumber]);
 | 
				
			||||||
 | 
					      queryClient.invalidateQueries(['device', serialNumber]);
 | 
				
			||||||
 | 
					      queryClient.invalidateQueries(['devices']);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -248,27 +250,14 @@ const startScript = (data: { serialNumber: string; timeout?: number; [k: string]
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
    .then((response: { data: DeviceCommandHistory }) => response.data);
 | 
					    .then((response: { data: DeviceCommandHistory }) => response.data);
 | 
				
			||||||
export const useDeviceScript = ({ serialNumber }: { serialNumber: string }) => {
 | 
					export const useDeviceScript = ({ serialNumber }: { serialNumber: string }) => {
 | 
				
			||||||
  const { t } = useTranslation();
 | 
					 | 
				
			||||||
  const toast = useToast();
 | 
					 | 
				
			||||||
  const queryClient = useQueryClient();
 | 
					  const queryClient = useQueryClient();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return useMutation(startScript, {
 | 
					  return useMutation(startScript, {
 | 
				
			||||||
    onSuccess: () => {
 | 
					    onSuccess: () => {
 | 
				
			||||||
      queryClient.invalidateQueries(['commands', serialNumber]);
 | 
					      queryClient.invalidateQueries(['commands', serialNumber]);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    onError: (e) => {
 | 
					    onError: () => {
 | 
				
			||||||
      queryClient.invalidateQueries(['commands', serialNumber]);
 | 
					      queryClient.invalidateQueries(['commands', serialNumber]);
 | 
				
			||||||
      if (axios.isAxiosError(e)) {
 | 
					 | 
				
			||||||
        toast({
 | 
					 | 
				
			||||||
          id: 'script-error',
 | 
					 | 
				
			||||||
          title: t('common.error'),
 | 
					 | 
				
			||||||
          description: e?.response?.data?.ErrorDescription,
 | 
					 | 
				
			||||||
          status: 'error',
 | 
					 | 
				
			||||||
          duration: 5000,
 | 
					 | 
				
			||||||
          isClosable: true,
 | 
					 | 
				
			||||||
          position: 'top-right',
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,6 @@ import { compactDate } from 'helpers/dateFormatting';
 | 
				
			|||||||
import { useGetDevice } from 'hooks/Network/Devices';
 | 
					import { useGetDevice } from 'hooks/Network/Devices';
 | 
				
			||||||
import { useGetProvUi } from 'hooks/Network/Endpoints';
 | 
					import { useGetProvUi } from 'hooks/Network/Endpoints';
 | 
				
			||||||
import { useGetTag } from 'hooks/Network/Inventory';
 | 
					import { useGetTag } from 'hooks/Network/Inventory';
 | 
				
			||||||
import { DeviceConfiguration } from 'models/Device';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
  serialNumber: string;
 | 
					  serialNumber: string;
 | 
				
			||||||
@@ -60,7 +59,7 @@ const DeviceDetails = ({ serialNumber }: Props) => {
 | 
				
			|||||||
        <Heading size="md">{t('common.details')}</Heading>
 | 
					        <Heading size="md">{t('common.details')}</Heading>
 | 
				
			||||||
        <Spacer />
 | 
					        <Spacer />
 | 
				
			||||||
        <ViewCapabilitiesModal serialNumber={serialNumber} />
 | 
					        <ViewCapabilitiesModal serialNumber={serialNumber} />
 | 
				
			||||||
        <ViewConfigurationModal configuration={getDevice.data?.configuration as DeviceConfiguration} />
 | 
					        <ViewConfigurationModal serialNumber={serialNumber} />
 | 
				
			||||||
      </CardHeader>
 | 
					      </CardHeader>
 | 
				
			||||||
      <CardBody display="block">
 | 
					      <CardBody display="block">
 | 
				
			||||||
        <Grid templateColumns="repeat(2, 1fr)" gap={0} w="100%">
 | 
					        <Grid templateColumns="repeat(2, 1fr)" gap={0} w="100%">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,9 @@ import {
 | 
				
			|||||||
  AccordionPanel,
 | 
					  AccordionPanel,
 | 
				
			||||||
  Box,
 | 
					  Box,
 | 
				
			||||||
  Button,
 | 
					  Button,
 | 
				
			||||||
 | 
					  Center,
 | 
				
			||||||
  IconButton,
 | 
					  IconButton,
 | 
				
			||||||
 | 
					  Spinner,
 | 
				
			||||||
  Tooltip,
 | 
					  Tooltip,
 | 
				
			||||||
  useClipboard,
 | 
					  useClipboard,
 | 
				
			||||||
  useColorMode,
 | 
					  useColorMode,
 | 
				
			||||||
@@ -17,19 +19,26 @@ import { JsonViewer } from '@textea/json-viewer';
 | 
				
			|||||||
import { Barcode } from '@phosphor-icons/react';
 | 
					import { Barcode } from '@phosphor-icons/react';
 | 
				
			||||||
import { useTranslation } from 'react-i18next';
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
import { Modal } from 'components/Modals/Modal';
 | 
					import { Modal } from 'components/Modals/Modal';
 | 
				
			||||||
import { DeviceConfiguration } from 'models/Device';
 | 
					import { useGetDevice } from 'hooks/Network/Devices';
 | 
				
			||||||
 | 
					import { RefreshButton } from 'components/Buttons/RefreshButton';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ViewConfigurationModal = ({ configuration }: { configuration?: DeviceConfiguration }) => {
 | 
					const ViewConfigurationModal = ({ serialNumber }: { serialNumber: string }) => {
 | 
				
			||||||
  const { t } = useTranslation();
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
 | 
					  const getDevice = useGetDevice({ serialNumber });
 | 
				
			||||||
  const { isOpen, onOpen, onClose } = useDisclosure();
 | 
					  const { isOpen, onOpen, onClose } = useDisclosure();
 | 
				
			||||||
  const { hasCopied, onCopy, setValue } = useClipboard(JSON.stringify(configuration ?? {}, null, 2));
 | 
					  const { hasCopied, onCopy, setValue } = useClipboard(JSON.stringify(getDevice.data?.configuration ?? {}, null, 2));
 | 
				
			||||||
  const { colorMode } = useColorMode();
 | 
					  const { colorMode } = useColorMode();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  React.useEffect(() => {
 | 
					  React.useEffect(() => {
 | 
				
			||||||
    if (configuration) {
 | 
					    if (getDevice.data) {
 | 
				
			||||||
      setValue(JSON.stringify(configuration, null, 2));
 | 
					      setValue(JSON.stringify(getDevice.data.configuration, null, 2));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [configuration]);
 | 
					  }, [getDevice.data?.configuration]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleOpenClick = () => {
 | 
				
			||||||
 | 
					    getDevice.refetch();
 | 
				
			||||||
 | 
					    onOpen();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
@@ -37,7 +46,7 @@ const ViewConfigurationModal = ({ configuration }: { configuration?: DeviceConfi
 | 
				
			|||||||
        <IconButton
 | 
					        <IconButton
 | 
				
			||||||
          aria-label={t('configurations.one')}
 | 
					          aria-label={t('configurations.one')}
 | 
				
			||||||
          icon={<Barcode size={20} />}
 | 
					          icon={<Barcode size={20} />}
 | 
				
			||||||
          onClick={onOpen}
 | 
					          onClick={handleOpenClick}
 | 
				
			||||||
          colorScheme="purple"
 | 
					          colorScheme="purple"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </Tooltip>
 | 
					      </Tooltip>
 | 
				
			||||||
@@ -45,14 +54,17 @@ const ViewConfigurationModal = ({ configuration }: { configuration?: DeviceConfi
 | 
				
			|||||||
        isOpen={isOpen}
 | 
					        isOpen={isOpen}
 | 
				
			||||||
        title={t('configurations.one')}
 | 
					        title={t('configurations.one')}
 | 
				
			||||||
        topRightButtons={
 | 
					        topRightButtons={
 | 
				
			||||||
          <Button onClick={onCopy} size="md" colorScheme="teal">
 | 
					          <>
 | 
				
			||||||
            {hasCopied ? `${t('common.copied')}!` : t('common.copy')}
 | 
					            <Button onClick={onCopy} size="md" colorScheme="teal">
 | 
				
			||||||
          </Button>
 | 
					              {hasCopied ? `${t('common.copied')}!` : t('common.copy')}
 | 
				
			||||||
 | 
					            </Button>
 | 
				
			||||||
 | 
					            <RefreshButton onClick={getDevice.refetch} isFetching={getDevice.isFetching} />
 | 
				
			||||||
 | 
					          </>
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        onClose={onClose}
 | 
					        onClose={onClose}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <Box display="inline-block" w="100%">
 | 
					        <Box display="inline-block" w="100%">
 | 
				
			||||||
          {configuration && (
 | 
					          {getDevice.data && !getDevice.isFetching ? (
 | 
				
			||||||
            <Box maxH="calc(100vh - 250px)" minH="300px" overflowY="auto">
 | 
					            <Box maxH="calc(100vh - 250px)" minH="300px" overflowY="auto">
 | 
				
			||||||
              <Accordion defaultIndex={0} allowToggle>
 | 
					              <Accordion defaultIndex={0} allowToggle>
 | 
				
			||||||
                <AccordionItem>
 | 
					                <AccordionItem>
 | 
				
			||||||
@@ -71,7 +83,7 @@ const ViewConfigurationModal = ({ configuration }: { configuration?: DeviceConfi
 | 
				
			|||||||
                      enableClipboard={false}
 | 
					                      enableClipboard={false}
 | 
				
			||||||
                      theme={colorMode === 'light' ? undefined : 'dark'}
 | 
					                      theme={colorMode === 'light' ? undefined : 'dark'}
 | 
				
			||||||
                      defaultInspectDepth={1}
 | 
					                      defaultInspectDepth={1}
 | 
				
			||||||
                      value={configuration as object}
 | 
					                      value={getDevice.data.configuration as object}
 | 
				
			||||||
                      style={{ background: 'unset', display: 'unset' }}
 | 
					                      style={{ background: 'unset', display: 'unset' }}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                  </AccordionPanel>
 | 
					                  </AccordionPanel>
 | 
				
			||||||
@@ -86,11 +98,15 @@ const ViewConfigurationModal = ({ configuration }: { configuration?: DeviceConfi
 | 
				
			|||||||
                    </AccordionButton>
 | 
					                    </AccordionButton>
 | 
				
			||||||
                  </h2>
 | 
					                  </h2>
 | 
				
			||||||
                  <AccordionPanel pb={4} overflowX="auto">
 | 
					                  <AccordionPanel pb={4} overflowX="auto">
 | 
				
			||||||
                    <pre>{JSON.stringify(configuration, null, 2)}</pre>
 | 
					                    <pre>{JSON.stringify(getDevice.data.configuration, null, 2)}</pre>
 | 
				
			||||||
                  </AccordionPanel>
 | 
					                  </AccordionPanel>
 | 
				
			||||||
                </AccordionItem>
 | 
					                </AccordionItem>
 | 
				
			||||||
              </Accordion>
 | 
					              </Accordion>
 | 
				
			||||||
            </Box>
 | 
					            </Box>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <Center my={12}>
 | 
				
			||||||
 | 
					              <Spinner size="xl" />
 | 
				
			||||||
 | 
					            </Center>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
        </Box>
 | 
					        </Box>
 | 
				
			||||||
      </Modal>
 | 
					      </Modal>
 | 
				
			||||||
@@ -98,4 +114,4 @@ const ViewConfigurationModal = ({ configuration }: { configuration?: DeviceConfi
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default ViewConfigurationModal;
 | 
					export default React.memo(ViewConfigurationModal);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user