Merge pull request #162 from stephb9959/main

[WIFI-12270] Now displaying information related to restricted device in dev mode
This commit is contained in:
Charles Bourque
2023-02-07 20:27:12 +01:00
committed by GitHub
13 changed files with 123 additions and 64 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "ucentral-client", "name": "ucentral-client",
"version": "2.9.0(9)", "version": "2.9.0(11)",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ucentral-client", "name": "ucentral-client",
"version": "2.9.0(9)", "version": "2.9.0(11)",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@chakra-ui/icons": "^2.0.11", "@chakra-ui/icons": "^2.0.11",

View File

@@ -1,6 +1,6 @@
{ {
"name": "ucentral-client", "name": "ucentral-client",
"version": "2.9.0(9)", "version": "2.9.0(11)",
"description": "", "description": "",
"private": true, "private": true,
"main": "index.tsx", "main": "index.tsx",

View File

@@ -630,6 +630,8 @@
"one": "Gerät", "one": "Gerät",
"reassign_already_owned": "Geräte neu zuweisen, die bereits vorhanden sind und einem anderen Unternehmen/Veranstaltungsort/Abonnenten gehören?", "reassign_already_owned": "Geräte neu zuweisen, die bereits vorhanden sind und einem anderen Unternehmen/Veranstaltungsort/Abonnenten gehören?",
"restricted": "Beschränkt", "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", "sanity": "Gesundheit",
"start_import": "Geräteimport starten", "start_import": "Geräteimport starten",
"test_batch": "Testen Sie Importdaten", "test_batch": "Testen Sie Importdaten",

View File

@@ -630,6 +630,8 @@
"one": "Device", "one": "Device",
"reassign_already_owned": "Reassign devices which already exist and are owned by another entity/venue/subscriber?", "reassign_already_owned": "Reassign devices which already exist and are owned by another entity/venue/subscriber?",
"restricted": "Restricted", "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", "sanity": "Sanity",
"start_import": "Start Device Importation", "start_import": "Start Device Importation",
"test_batch": "Test Import Data", "test_batch": "Test Import Data",

View File

@@ -630,6 +630,8 @@
"one": "Dispositivo", "one": "Dispositivo",
"reassign_already_owned": "¿Reasignar dispositivos que ya existen y son propiedad de otra entidad/lugar/suscriptor?", "reassign_already_owned": "¿Reasignar dispositivos que ya existen y son propiedad de otra entidad/lugar/suscriptor?",
"restricted": "Restringido", "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", "sanity": "Cordura",
"start_import": "Iniciar la importación de dispositivos", "start_import": "Iniciar la importación de dispositivos",
"test_batch": "Datos de importación de prueba", "test_batch": "Datos de importación de prueba",

View File

@@ -630,6 +630,8 @@
"one": "Dispositif", "one": "Dispositif",
"reassign_already_owned": "Réattribuer des appareils qui existent déjà et qui appartiennent à une autre entité/salle/abonné ?", "reassign_already_owned": "Réattribuer des appareils qui existent déjà et qui appartiennent à une autre entité/salle/abonné ?",
"restricted": "Limité", "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", "sanity": "Santé mentale",
"start_import": "Démarrer l'importation de l'appareil", "start_import": "Démarrer l'importation de l'appareil",
"test_batch": "Tester les données d'importation", "test_batch": "Tester les données d'importation",

View File

@@ -630,6 +630,8 @@
"one": "Dispositivo", "one": "Dispositivo",
"reassign_already_owned": "Reatribuir dispositivos que já existem e são de propriedade de outra entidade/local/assinante?", "reassign_already_owned": "Reatribuir dispositivos que já existem e são de propriedade de outra entidade/local/assinante?",
"restricted": "Restrito", "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", "sanity": "Sanidade",
"start_import": "Iniciar importação de dispositivos", "start_import": "Iniciar importação de dispositivos",
"test_batch": "Dados de importação de teste", "test_batch": "Dados de importação de teste",

View File

@@ -57,7 +57,8 @@ export const FirmwareUpgradeModal = ({ modalProps: { isOpen, onClose }, serialNu
upgrade({ upgrade({
keepRedirector: isRedirector, keepRedirector: isRedirector,
uri, uri,
signature: device?.restrictedDevice ? ref.current?.values?.signature : undefined, signature:
device?.restrictedDevice && !device?.restrictionDetails?.developer ? ref.current?.values?.signature : undefined,
}); });
}; };
@@ -89,7 +90,7 @@ export const FirmwareUpgradeModal = ({ modalProps: { isOpen, onClose }, serialNu
</FormLabel> </FormLabel>
<Switch isChecked={isRedirector} onChange={toggle} borderRadius="15px" size="lg" /> <Switch isChecked={isRedirector} onChange={toggle} borderRadius="15px" size="lg" />
</FormControl> </FormControl>
{device?.restrictedDevice && ( {device?.restrictedDevice && !device?.restrictionDetails?.developer && (
<Formik<{ signature?: string }> <Formik<{ signature?: string }>
innerRef={ref as Ref<FormikProps<{ signature?: string | undefined }>> | undefined} innerRef={ref as Ref<FormikProps<{ signature?: string | undefined }>> | undefined}
key={formKey} key={formKey}

View File

@@ -183,7 +183,9 @@ const CustomScriptForm = ({
<> <>
<Flex> <Flex>
<Box> <Box>
{device?.restrictedDevice && <SignatureField name="signature" isDisabled={areFieldsDisabled} />} {device?.restrictedDevice && !device?.restrictionDetails?.developer && (
<SignatureField name="signature" isDisabled={areFieldsDisabled} />
)}
</Box> </Box>
</Flex> </Flex>
<SelectField <SelectField

View File

@@ -76,7 +76,7 @@ export const ScriptModal = ({ device, modalProps }: ScriptModalProps) => {
when: 0, when: 0,
deferred: data.deferred, deferred: data.deferred,
timeout: data.timeout, timeout: data.timeout,
signature: device?.restrictedDevice ? data.signature : undefined, signature: device?.restrictedDevice && !device?.restrictionDetails?.developer ? data.signature : undefined,
uri: data.defaultUploadURI && data.defaultUploadURI?.length > 0 ? data.defaultUploadURI : undefined, uri: data.defaultUploadURI && data.defaultUploadURI?.length > 0 ? data.defaultUploadURI : undefined,
scriptId: selectedScript, scriptId: selectedScript,
type: data.type, type: data.type,

View File

@@ -1,5 +1,16 @@
import * as React from 'react'; import * as React from 'react';
import { Box, Flex, Heading, ListItem, Text, UnorderedList } from '@chakra-ui/react'; import {
Box,
Flex,
Heading,
ListItem,
Tag,
TagLabel,
TagLeftIcon,
Text,
Tooltip,
UnorderedList,
} from '@chakra-ui/react';
import { LockSimple, LockSimpleOpen } from 'phosphor-react'; import { LockSimple, LockSimpleOpen } from 'phosphor-react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Card } from 'components/Containers/Card'; import { Card } from 'components/Containers/Card';
@@ -20,7 +31,7 @@ const RestrictionsCard = ({ serialNumber }: Props) => {
ssh: 'SSH', ssh: 'SSH',
rtty: 'RTTY', rtty: 'RTTY',
tty: t('restrictions.tty'), tty: t('restrictions.tty'),
developer: t('restrictions.developer'), // developer: t('restrictions.developer'),
upgrade: t('restrictions.signed_upgrade'), upgrade: t('restrictions.signed_upgrade'),
commands: t('restrictions.gw_commands'), commands: t('restrictions.gw_commands'),
} as { [key: string]: string }; } as { [key: string]: string };
@@ -38,27 +49,52 @@ const RestrictionsCard = ({ serialNumber }: Props) => {
return restrictedKeys.map(([k]) => <ListItem key={k}>{LABELS[k]}</ListItem>); return restrictedKeys.map(([k]) => <ListItem key={k}>{LABELS[k]}</ListItem>);
}; };
const isMissingSigningInfo =
!restrictions.key_info ||
(!restrictions.key_info.algo && !restrictions.key_info.vendor) ||
(restrictions.key_info.algo.length === 0 && restrictions.key_info.vendor.length === 0);
return ( return (
<Card mb={4}> <Card mb={4}>
<CardHeader> <CardHeader>
<Heading size="md">{t('restrictions.title')}</Heading> <Heading size="md" my="auto" mr={2}>
{t('restrictions.title')}
</Heading>
{getDevice.data?.restrictionDetails?.developer ? (
<Tooltip label={t('devices.restricted_overriden')} hasArrow>
<Tag size="lg" colorScheme="green">
<TagLeftIcon boxSize="18px" as={LockSimpleOpen} />
<TagLabel>{t('devices.restrictions_overriden_title')}</TagLabel>
</Tag>
</Tooltip>
) : null}
</CardHeader> </CardHeader>
<CardBody p={0} display="block"> <CardBody p={0} display="block">
<Flex mt={2}> <Flex mt={2}>
<Heading size="sm" mr={2}> <Heading size="sm" mr={2} my="auto">
{t('restrictions.countries')}: {t('restrictions.countries')}:
</Heading> </Heading>
<Text>{restrictions.country.join(', ')}</Text> <Text my="auto">
{restrictions.country?.length === 0 ? t('common.all') : restrictions.country.join(', ')}
</Text>
</Flex> </Flex>
<Heading size="sm" mt={2}> <Flex mt={2}>
{t('restrictions.key_verification')} <Heading size="sm" mt={2} my="auto">
{t('restrictions.key_verification')} {isMissingSigningInfo ? ':' : ''}
</Heading> </Heading>
<UnorderedList> {isMissingSigningInfo ? (
<Text my="auto" ml={2}>
{t('common.none')}
</Text>
) : null}
</Flex>
<UnorderedList hidden={isMissingSigningInfo}>
<ListItem> <ListItem>
{t('controller.wifi.vendor')}: {restrictions.key_info?.vendor} {t('controller.wifi.vendor')}:{' '}
{restrictions.key_info?.vendor?.length > 0 ? restrictions.key_info?.vendor : '-'}
</ListItem> </ListItem>
<ListItem> <ListItem>
{t('restrictions.algo')}: {restrictions.key_info?.algo} {t('restrictions.algo')}: {restrictions.key_info?.algo?.length > 0 ? restrictions.key_info?.algo : '-'}
</ListItem> </ListItem>
</UnorderedList> </UnorderedList>
<Flex mt={2}> <Flex mt={2}>

View File

@@ -13,7 +13,7 @@ import {
useColorModeValue, useColorModeValue,
useDisclosure, useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { Heart, HeartBreak, LockSimple, WifiHigh, WifiSlash } from 'phosphor-react'; import { Heart, HeartBreak, LockSimple, LockSimpleOpen, WifiHigh, WifiSlash } from 'phosphor-react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Masonry from 'react-masonry-css'; import Masonry from 'react-masonry-css';
import DeviceDetails from './Details'; import DeviceDetails from './Details';
@@ -59,6 +59,9 @@ const DevicePageWrapper = ({ serialNumber }: Props) => {
const traceModalProps = useDisclosure(); const traceModalProps = useDisclosure();
const rebootModalProps = useDisclosure(); const rebootModalProps = useDisclosure();
const scriptModal = useScriptModal(); const scriptModal = useScriptModal();
// Sticky-top styles
const isCompact = breakpoint === 'base' || breakpoint === 'sm' || breakpoint === 'md';
const boxShadow = useColorModeValue('0px 7px 23px rgba(0, 0, 0, 0.05)', 'none');
const connectedTag = React.useMemo(() => { const connectedTag = React.useMemo(() => {
if (!getStatus.data) return null; if (!getStatus.data) return null;
@@ -102,9 +105,28 @@ const DevicePageWrapper = ({ serialNumber }: Props) => {
); );
}, [getStatus.data, getHealth.data]); }, [getStatus.data, getHealth.data]);
// Sticky-top styles const restrictedTag = React.useMemo(() => {
const isCompact = breakpoint === 'base' || breakpoint === 'sm' || breakpoint === 'md'; if (!getDevice.data || !getDevice.data.restrictedDevice) return null;
const boxShadow = useColorModeValue('0px 7px 23px rgba(0, 0, 0, 0.05)', 'none');
if (getDevice.data.restrictionDetails?.developer)
return (
<Tooltip label={t('devices.restricted_overriden')} hasArrow>
<Tag size="lg" colorScheme="green">
<TagLeftIcon boxSize="18px" as={LockSimpleOpen} />
<TagLabel>
{t('devices.restricted')} {isCompact ? '' : '(Dev Mode)'}
</TagLabel>
</Tag>
</Tooltip>
);
return (
<Tag size="lg" colorScheme="red">
<TagLeftIcon boxSize="18px" as={LockSimple} />
<TagLabel>{t('devices.restricted')}</TagLabel>
</Tag>
);
}, [getDevice.data, isCompact]);
const refresh = () => { const refresh = () => {
getDevice.refetch(); getDevice.refetch();
@@ -121,12 +143,7 @@ const DevicePageWrapper = ({ serialNumber }: Props) => {
<Heading size="md">{serialNumber}</Heading> <Heading size="md">{serialNumber}</Heading>
{connectedTag} {connectedTag}
{healthTag} {healthTag}
{getDevice.data?.restrictedDevice && ( {restrictedTag}
<Tag size="lg" colorScheme="gray">
<TagLeftIcon boxSize="18px" as={LockSimple} />
<TagLabel>{t('devices.restricted')}</TagLabel>
</Tag>
)}
</HStack> </HStack>
<Spacer /> <Spacer />
<HStack spacing={2}> <HStack spacing={2}>
@@ -175,12 +192,7 @@ const DevicePageWrapper = ({ serialNumber }: Props) => {
<Heading size="md">{serialNumber}</Heading> <Heading size="md">{serialNumber}</Heading>
{connectedTag} {connectedTag}
{healthTag} {healthTag}
{getDevice.data?.restrictedDevice && ( {restrictedTag}
<Tag size="lg" colorScheme="gray">
<TagLeftIcon boxSize="18px" as={LockSimple} />
<TagLabel>{t('devices.restricted')}</TagLabel>
</Tag>
)}
</HStack> </HStack>
<Spacer /> <Spacer />
<HStack spacing={2}> <HStack spacing={2}>

View File

@@ -1,27 +1,16 @@
import * as React from 'react'; import * as React from 'react';
import { import { FormControl, FormErrorMessage, FormLabel, Input, Textarea, useDisclosure, useToast } from '@chakra-ui/react';
Alert,
AlertDescription,
AlertIcon,
AlertTitle,
Box,
FormControl,
FormErrorMessage,
FormLabel,
Input,
Textarea,
useDisclosure,
useToast,
} from '@chakra-ui/react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { CreateButton } from 'components/Buttons/CreateButton'; import { CreateButton } from 'components/Buttons/CreateButton';
import { SaveButton } from 'components/Buttons/SaveButton'; import { SaveButton } from 'components/Buttons/SaveButton';
import { Modal } from 'components/Modals/Modal'; import { Modal } from 'components/Modals/Modal';
import { useCreateBlacklist } from 'hooks/Network/Blacklist'; import { useCreateBlacklist } from 'hooks/Network/Blacklist';
import { AxiosError } from 'models/Axios';
const CreateBlacklistModal = () => { const CreateBlacklistModal = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const toast = useToast(); const toast = useToast();
const initialRef = React.useRef<HTMLInputElement>(null);
const modalProps = useDisclosure(); const modalProps = useDisclosure();
const createDevice = useCreateBlacklist(); const createDevice = useCreateBlacklist();
const [serialNumber, setSerialNumber] = React.useState<string>(''); const [serialNumber, setSerialNumber] = React.useState<string>('');
@@ -43,41 +32,50 @@ const CreateBlacklistModal = () => {
}); });
modalProps.onClose(); modalProps.onClose();
}, },
onError: (e) => {
toast({
id: 'add-blacklist-error',
title: t('common.error'),
description: (e as AxiosError)?.response?.data?.ErrorDescription,
status: 'error',
duration: 5000,
isClosable: true,
position: 'top-right',
});
},
}, },
); );
}; };
const isSerialValid = serialNumber.length === 12 && serialNumber.match('^[a-fA-F0-9]+$') !== null; const isSerialValid = serialNumber.length === 12 && serialNumber.match('^[a-fA-F0-9]+$') !== null;
React.useEffect(() => { const onOpen = () => {
setSerialNumber(''); setSerialNumber('');
setReason(''); setReason('');
}, [modalProps.isOpen]); modalProps.onOpen();
setTimeout(() => {
initialRef.current?.focus();
}, 200);
};
return ( return (
<> <>
<CreateButton onClick={modalProps.onOpen} isCompact ml={2} /> <CreateButton onClick={onOpen} isCompact ml={2} />
<Modal <Modal
{...modalProps} {...modalProps}
title={t('controller.devices.add_blacklist')} title={t('controller.devices.add_blacklist')}
topRightButtons={<SaveButton onClick={onSave} isLoading={createDevice.isLoading} isCompact />} topRightButtons={<SaveButton onClick={onSave} isLoading={createDevice.isLoading} isCompact />}
> >
<> <>
{createDevice.error && (
<Alert status="error" mb={4}>
<AlertIcon />
<Box>
<AlertTitle>{t('common.error')}</AlertTitle>
{
// @ts-ignore
<AlertDescription>{createDevice.error?.response?.data?.ErrorDescription}</AlertDescription>
}
</Box>
</Alert>
)}
<FormControl isInvalid={!isSerialValid} mb={2}> <FormControl isInvalid={!isSerialValid} mb={2}>
<FormLabel>{t('inventory.serial_number')}</FormLabel> <FormLabel>{t('inventory.serial_number')}</FormLabel>
<Input type="text" onChange={(e) => setSerialNumber(e.target.value)} value={serialNumber} w="140px" /> <Input
type="text"
onChange={(e) => setSerialNumber(e.target.value)}
value={serialNumber}
w="140px"
ref={initialRef}
/>
<FormErrorMessage>{t('inventory.invalid_serial_number')}</FormErrorMessage> <FormErrorMessage>{t('inventory.invalid_serial_number')}</FormErrorMessage>
</FormControl> </FormControl>
<FormControl> <FormControl>