Files
OptimCloud-gw-ui/src/pages/Device/WifiAnalysis/AssocationsTable.tsx
2024-06-04 08:55:35 -04:00

227 lines
6.0 KiB
TypeScript

import * as React from 'react';
import { Box, Flex, Heading, Spacer } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
import { ParsedRadio } from './RadiosTable';
import { ColumnPicker } from 'components/DataTables/ColumnPicker';
import { DataTable } from 'components/DataTables/DataTable';
import DataCell from 'components/TableCells/DataCell';
import { Column } from 'models/Table';
import IpCell from './IpCell';
export type ParsedAssociation = {
radio?: ParsedRadio;
ips: {
ipv4: string[];
ipv6: string[];
};
station: string;
ssid: string;
rssi: number | string;
mode: string;
rxBytes: number;
rxRate: number;
rxMcs: number | string;
rxNss: number | string;
txBytes: number;
txRate: number;
txMcs: number | string;
txNss: number | string;
recorded: number;
dynamicVlan?: number;
fingerprint?: object;
};
type Props = {
data?: ParsedAssociation[];
ouis?: Record<string, string>;
isSingle?: boolean;
};
const WifiAnalysisAssociationsTable = ({ data, ouis, isSingle }: Props) => {
const { t } = useTranslation();
const [hiddenColumns, setHiddenColumns] = React.useState<string[]>([]);
const vendorCell = React.useCallback((v: string) => ouis?.[v] ?? '', [ouis]);
const rightAlignedCell = React.useCallback(
(v: string | number) => (
<Box textAlign="right" pr={4}>
{v}
</Box>
),
[],
);
const dataCell = React.useCallback((v: number) => <DataCell bytes={v} />, []);
const indexCell = React.useCallback((assoc: ParsedAssociation) => assoc.radio?.band ?? assoc.radio?.deductedBand, []);
const ipCell = React.useCallback(
(assoc: ParsedAssociation) => <IpCell ipv4={assoc.ips.ipv4} ipv6={assoc.ips.ipv6} />,
[],
);
const columns: Column<ParsedAssociation>[] = React.useMemo(
(): Column<ParsedAssociation>[] => [
{
id: 'index',
Header: '',
Footer: '',
accessor: 'radio.index',
Cell: ({ cell }) => indexCell(cell.row.original) ?? '',
customWidth: '35px',
alwaysShow: true,
disableSortBy: true,
},
{
id: 'station',
Header: t('controller.wifi.station'),
Footer: '',
accessor: 'station',
customWidth: '35px',
isMonospace: true,
alwaysShow: true,
},
{
id: 'ssid',
Header: 'SSID',
Footer: '',
accessor: 'ssid',
customWidth: '35px',
alwaysShow: true,
},
{
id: 'ips',
Header: 'IPs',
Footer: '',
Cell: (v) => ipCell(v.cell.row.original),
disableSortBy: true,
},
{
id: 'fingerprint',
Header: 'Fingerprint',
Footer: '',
Cell: (v) => Object.values(v.cell.row.original.fingerprint ?? {}).join(', '),
disableSortBy: true,
},
{
id: 'vendor',
Header: t('controller.wifi.vendor'),
Footer: '',
accessor: 'vendor',
Cell: (v) => vendorCell(v.cell.row.original.station),
customWidth: '35px',
disableSortBy: true,
},
{
id: 'dynamicVlan',
Header: 'VLAN',
Footer: '',
Cell: (v) => (v.cell.row.original.dynamicVlan !== undefined ? `${v.cell.row.original.dynamicVlan}` : '-'),
accessor: 'txBytes',
customWidth: '35px',
},
{
id: 'mode',
Header: t('controller.wifi.mode'),
Footer: '',
accessor: 'mode',
customWidth: '35px',
disableSortBy: true,
},
{
id: 'rssi',
Header: 'RSSI',
Footer: '',
accessor: 'rssi',
Cell: (v) => rightAlignedCell(v.cell.row.original.rssi),
customWidth: '35px',
},
{
id: 'rxRate',
Header: t('controller.wifi.rx_rate'),
Footer: '',
accessor: 'rxRate',
Cell: (v) => rightAlignedCell(v.cell.row.original.rxRate),
customWidth: '35px',
},
{
id: 'rx',
Header: 'Rx',
Footer: '',
accessor: 'rxBytes',
Cell: (v) => dataCell(v.cell.row.original.rxBytes),
customWidth: '35px',
},
{
id: 'rxMcs',
Header: 'Rx MCS',
Footer: '',
accessor: 'rxMcs',
Cell: (v) => rightAlignedCell(v.cell.row.original.rxMcs),
customWidth: '35px',
},
{
id: 'rxNss',
Header: 'Rx NSS',
Footer: '',
accessor: 'rxNss',
Cell: (v) => rightAlignedCell(v.cell.row.original.rxNss),
customWidth: '35px',
},
{
id: 'txRate',
Header: t('controller.wifi.tx_rate'),
Footer: '',
accessor: 'txRate',
Cell: (v) => rightAlignedCell(v.cell.row.original.txRate),
customWidth: '35px',
},
{
id: 'txBytes',
Header: 'Tx',
Footer: '',
Cell: (v) => dataCell(v.cell.row.original.txBytes),
accessor: 'txBytes',
customWidth: '35px',
},
],
[t, ouis],
);
return (
<>
<Flex mt={2}>
<Heading size="sm" my="auto">
{isSingle ? 'Association' : `${t('devices.associations')} (${data?.length})`}
</Heading>
<Spacer />
<ColumnPicker
columns={columns as Column<unknown>[]}
hiddenColumns={hiddenColumns}
setHiddenColumns={setHiddenColumns}
preference="gateway.device.analysis.associations.hiddenColumns"
size="sm"
/>
</Flex>
<Box overflowX="auto" overflowY="auto" w="100%" maxH="300px">
<DataTable
columns={
columns as {
id: string;
Header: string;
Footer: string;
accessor: string;
}[]
}
hiddenColumns={hiddenColumns}
data={data ?? []}
hideEmptyListText
sortBy={[{ id: 'index', desc: true }]}
// @ts-ignore
hideControls
showAllRows
/>
</Box>
</>
);
};
export default WifiAnalysisAssociationsTable;