import * as React from 'react';
import { Box, Button, Heading, Image, Spacer, Tooltip, useDisclosure } from '@chakra-ui/react';
import { LockSimple } from 'phosphor-react';
import ReactCountryFlag from 'react-country-flag';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import Actions from './Actions';
import DeviceSearchBar from './DeviceSearchBar';
import DeviceListFirmwareButton from './FirmwareButton';
import AP from './icons/AP.png';
import IOT from './icons/IOT.png';
import MESH from './icons/MESH.png';
import SWITCH from './icons/SWITCH.png';
import { RefreshButton } from 'components/Buttons/RefreshButton';
import { CardBody } from 'components/Containers/Card/CardBody';
import { CardHeader } from 'components/Containers/Card/CardHeader';
import { ColumnPicker } from 'components/DataTables/ColumnPicker';
import { DataTable } from 'components/DataTables/DataTable';
import FormattedDate from 'components/InformationDisplays/FormattedDate';
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 { useScriptModal } from 'components/Modals/ScriptModal/useScriptModal';
import { TelemetryModal } from 'components/Modals/TelemetryModal';
import { TraceModal } from 'components/Modals/TraceModal';
import { WifiScanModal } from 'components/Modals/WifiScanModal';
import DataCell from 'components/TableCells/DataCell';
import NumberCell from 'components/TableCells/NumberCell';
import { DeviceWithStatus, useGetDeviceCount, useGetDevices } from 'hooks/Network/Devices';
import { FirmwareAgeResponse, useGetFirmwareAges } from 'hooks/Network/Firmware';
import { Column, PageInfo } from 'models/Table';
const ICON_STYLE = { width: '24px', height: '24px', borderRadius: '20px' };
const ICONS = {
AP: ,
SWITCH: ,
IOT: ,
MESH: ,
};
const BADGE_COLORS: Record = {
VALID_CERTIFICATE: 'red',
NO_CERTIFICATE: 'red',
MISMATCH_SERIAL: 'yellow',
VERIFIED: 'green',
};
const DeviceListCard = () => {
const { t } = useTranslation();
const navigate = useNavigate();
const [serialNumber, setSerialNumber] = React.useState('');
const [hiddenColumns, setHiddenColumns] = React.useState([]);
const [pageInfo, setPageInfo] = React.useState(undefined);
const scanModalProps = useDisclosure();
const resetModalProps = useDisclosure();
const upgradeModalProps = useDisclosure();
const traceModalProps = useDisclosure();
const eventQueueProps = useDisclosure();
const telemetryModalProps = useDisclosure();
const configureModalProps = useDisclosure();
const scriptModal = useScriptModal();
const getCount = useGetDeviceCount({ enabled: true });
const getDevices = useGetDevices({
pageInfo,
enabled: true,
});
const getAges = useGetFirmwareAges({
serialNumbers: getDevices.data?.devicesWithStatus.map((device) => device.serialNumber),
});
const onOpenScan = (serial: string) => {
setSerialNumber(serial);
scanModalProps.onOpen();
};
const onOpenFactoryReset = (serial: string) => {
setSerialNumber(serial);
resetModalProps.onOpen();
};
const onOpenUpgradeModal = (serial: string) => {
setSerialNumber(serial);
upgradeModalProps.onOpen();
};
const onOpenTrace = (serial: string) => {
setSerialNumber(serial);
traceModalProps.onOpen();
};
const onOpenEventQueue = (serial: string) => {
setSerialNumber(serial);
eventQueueProps.onOpen();
};
const onOpenTelemetry = (serial: string) => {
setSerialNumber(serial);
telemetryModalProps.onOpen();
};
const onOpenConfigure = (serial: string) => {
setSerialNumber(serial);
configureModalProps.onOpen();
};
const goToSerial = (serial: string) => () => {
navigate(`/devices/${serial}`);
};
const badgeCell = React.useCallback(
(device: DeviceWithStatus) => (
{ICONS[device.deviceType] ?? ICONS.AP}
{device.restrictedDevice && (
)}
),
[],
);
const serialCell = React.useCallback(
(device: DeviceWithStatus) => (
),
[],
);
const dataCell = React.useCallback(
(v: number) => (
),
[],
);
const dateCell = React.useCallback(
(v?: number | string, hidePrefix?: boolean) =>
v !== undefined && typeof v === 'number' && v !== 0 ? (
) : (
'-'
),
[],
);
const firmwareCell = React.useCallback(
(device: DeviceWithStatus & { age?: FirmwareAgeResponse }) => (
),
[getAges],
);
const localeCell = React.useCallback(
(device: DeviceWithStatus) => (
{device.locale !== '' && device.ipAddress !== '' && (
)}
{` ${device.ipAddress}`}
),
[],
);
const numberCell = React.useCallback((v?: number) => , []);
const actionCell = React.useCallback(
(device: DeviceWithStatus) => (
),
[],
);
const columns: Column[] = React.useMemo(
(): Column[] => [
{
id: 'badge',
Header: '',
Footer: '',
accessor: 'badge',
Cell: (v) => badgeCell(v.cell.row.original),
customWidth: '35px',
alwaysShow: true,
disableSortBy: true,
},
{
id: 'serialNumber',
Header: t('inventory.serial_number'),
Footer: '',
accessor: 'serialNumber',
Cell: (v) => serialCell(v.cell.row.original),
alwaysShow: true,
customMaxWidth: '200px',
customWidth: '130px',
customMinWidth: '130px',
disableSortBy: true,
},
{
id: 'firmware',
Header: t('commands.revision'),
Footer: '',
accessor: 'firmware',
Cell: (v) => firmwareCell(v.cell.row.original),
customWidth: '50px',
disableSortBy: true,
},
{
id: 'compatible',
Header: t('common.type'),
Footer: '',
accessor: 'compatible',
customWidth: '50px',
disableSortBy: true,
},
{
id: 'IP',
Header: 'IP',
Footer: '',
accessor: 'IP',
Cell: (v) => localeCell(v.cell.row.original),
disableSortBy: true,
},
{
id: 'lastContact',
Header: t('analytics.last_contact'),
Footer: '',
accessor: 'lastContact',
Cell: (v) => dateCell(v.cell.row.original.lastContact),
disableSortBy: true,
},
{
id: 'lastFWUpdate',
Header: t('controller.devices.last_upgrade'),
Footer: '',
accessor: 'lastFWUpdate',
Cell: (v) => dateCell(v.cell.row.original.lastFWUpdate),
disableSortBy: true,
},
{
id: 'rxBytes',
Header: 'Rx',
Footer: '',
accessor: 'rxBytes',
Cell: (v) => dataCell(v.cell.row.original.rxBytes),
customWidth: '50px',
disableSortBy: true,
},
{
id: 'txBytes',
Header: 'Tx',
Footer: '',
accessor: 'txBytes',
Cell: (v) => dataCell(v.cell.row.original.txBytes),
customWidth: '50px',
disableSortBy: true,
},
{
id: '2G',
Header: '2G',
Footer: '',
accessor: 'associations_2G',
Cell: (v) => numberCell(v.cell.row.original.associations_2G),
customWidth: '50px',
disableSortBy: true,
},
{
id: '5G',
Header: '5G',
Footer: '',
accessor: 'associations_5G',
Cell: (v) => numberCell(v.cell.row.original.associations_5G),
customWidth: '50px',
disableSortBy: true,
},
{
id: '6G',
Header: '6G',
Footer: '',
accessor: 'associations_6G',
Cell: (v) => numberCell(v.cell.row.original.associations_6G),
customWidth: '50px',
disableSortBy: true,
},
{
id: 'certificateExpiryDate',
Header: t('devices.certificate_expiry'),
Footer: '',
accessor: 'certificateExpiryDate',
Cell: (v) => dateCell(v.cell.row.original.certificateExpiryDate, true),
customWidth: '50px',
disableSortBy: true,
},
{
id: 'actions',
Header: t('common.actions'),
Footer: '',
accessor: 'actions',
Cell: (v) => actionCell(v.cell.row.original),
customWidth: '50px',
alwaysShow: true,
disableSortBy: true,
},
],
[t, firmwareCell],
);
const data = React.useMemo(() => {
if (!getDevices.data) return [];
return getDevices.data.devicesWithStatus.map((device) => ({
...device,
age: getAges?.data?.ages.find(({ serialNumber: devSerial }) => devSerial === device.serialNumber),
}));
}, [getAges, getDevices]);
return (
<>
{getCount.data?.count} {t('devices.title')}
[]}
hiddenColumns={hiddenColumns}
setHiddenColumns={setHiddenColumns}
preference="gateway.devices.table.hiddenColumns"
/>
{
getDevices.refetch();
getCount.refetch();
}}
isCompact
ml={2}
isFetching={getCount.isFetching || getDevices.isFetching}
/>
!hiddenColumns.find((hidden) => hidden === id)) as {
id: string;
Header: string;
Footer: string;
accessor: string;
}[]
}
data={data ?? []}
isLoading={getCount.isFetching || getDevices.isFetching}
isManual
hiddenColumns={hiddenColumns}
obj={t('devices.title')}
count={getCount.data?.count || 0}
// @ts-ignore
setPageInfo={setPageInfo}
saveSettingsId="gateway.devices.table"
minHeight="600px"
/>
{scriptModal.modal}
>
);
};
export default React.memo(DeviceListCard);