From 9a15fdbb1003e9a805635fc3f3c793c566681092 Mon Sep 17 00:00:00 2001 From: nurikk Date: Sun, 21 Nov 2021 10:05:05 +0800 Subject: [PATCH] feat(ota): refactor table --- src/components/grid/ReactTableCom.tsx | 105 +++++++++++++++++++++++ src/components/ota-page/index.tsx | 85 +++++++++++-------- src/components/zigbee/ReactTableCom.tsx | 106 ------------------------ src/components/zigbee/index.tsx | 8 +- 4 files changed, 159 insertions(+), 145 deletions(-) create mode 100644 src/components/grid/ReactTableCom.tsx delete mode 100644 src/components/zigbee/ReactTableCom.tsx diff --git a/src/components/grid/ReactTableCom.tsx b/src/components/grid/ReactTableCom.tsx new file mode 100644 index 000000000..b8a716b70 --- /dev/null +++ b/src/components/grid/ReactTableCom.tsx @@ -0,0 +1,105 @@ +import React from "react"; +import { useTable, useSortBy, HeaderGroup, Column, useAsyncDebounce, useGlobalFilter } from 'react-table' + +import cx from "classnames"; +import { useTranslation } from "react-i18next"; + +interface Props { + columns: Array>; + data: Array; +} + +function GlobalFilter({ + globalFilter, + setGlobalFilter, +}) { + const [value, setValue] = React.useState(globalFilter) + const onChange = useAsyncDebounce(value => { + setGlobalFilter(value || undefined) + }, 200); + + const { t } = useTranslation(['common']) + + return ( + + { + setValue(e.target.value); + onChange(e.target.value); + }} + placeholder={t('common:enter_search_criteria')} + className="form-control" + /> + + ) +} + +export const Table: React.FC = ({ columns, data }) => { + + const { + getTableProps, + getTableBodyProps, + headerGroups, + rows, + prepareRow, + state, + visibleColumns, + setGlobalFilter, + } = useTable( + { + columns, + data, + }, + useGlobalFilter, + useSortBy + ) + + + return ( + + + + + + {headerGroups.map((headerGroup: HeaderGroup) => ( + + {headerGroup.headers.map(column => ( + + ))} + + ))} + + + + {rows.map( + (row, i) => { + prepareRow(row); + return ( + + {row.cells.map(cell => )} + + ) + } + )} + +
+ +
+ {column.render('Header')} + + {column.isSorted + ? column.isSortedDesc + ? + : + : } + +
{cell.render('Cell')}
+ + ) +} \ No newline at end of file diff --git a/src/components/ota-page/index.tsx b/src/components/ota-page/index.tsx index 6054a2cab..bd3812f37 100644 --- a/src/components/ota-page/index.tsx +++ b/src/components/ota-page/index.tsx @@ -11,6 +11,8 @@ import { Link } from "react-router-dom"; import { Device, DeviceState, OTAState } from "../../types"; import { VendorLink, ModelLink, OTALink } from "../vendor-links/verndor-links"; import { useTranslation, WithTranslation, withTranslation } from "react-i18next"; +import { Column } from "react-table"; +import { Table } from "../grid/ReactTableCom"; type OtaRowProps = { @@ -39,57 +41,70 @@ const StateCell: FunctionComponent = (props) => { } } -const OtaRow: FunctionComponent = (props) => { - const { device, state, ...rest } = props; - return - {device.friendly_name} - - - {device.date_code} - - - - - -} type PropsFromStore = Pick; +type OtaGridData = { + id: string; + device: Device; + state: DeviceState; +} class OtaPage extends Component, unknown> { getAllOtaDevices() { - const { devices } = this.props; - return Object.values(devices).filter(device => device?.definition?.supports_ota) + const { devices, deviceStates } = this.props; + return Object.values(devices) + .filter(device => device?.definition?.supports_ota) + .map((device) => { + const state = deviceStates[device.friendly_name] ?? {} as DeviceState; + return { id: device.friendly_name, device, state } as OtaGridData; + }) } checkAllOTA = () => { const { checkOTA } = this.props; const otaDevices = this.getAllOtaDevices(); - otaDevices.forEach(device => checkOTA(device.friendly_name)); + otaDevices.forEach(({ device }) => checkOTA(device.friendly_name)); } render() { - const { deviceStates, checkOTA, updateOTA, t } = this.props; + const { checkOTA, updateOTA, t } = this.props; const otaApi = { checkOTA, updateOTA }; const otaDevices = this.getAllOtaDevices(); + const columns: Column[] = [ + { + Header: t('zigbee:friendly_name') as string, + accessor: ({ device }) => device.friendly_name, + Cell: ({ row: { original: { device } } }) => {device.friendly_name} + + }, + { + Header: t('zigbee:manufacturer') as string, + accessor: ({ device }) => [device.manufacturer, device.definition?.vendor].join(' '), + Cell: ({ row: { original: { device } } }) => + }, + { + Header: t('zigbee:model') as string, + accessor: ({ device }) => [device.model_id, device.definition?.model].join(' '), + Cell: ({ row: { original: { device } } }) => + }, + { + Header: t('zigbee:firmware_build_date') as string, + accessor: ({ device }) => device.date_code + + }, + { + Header: t('zigbee:firmware_version') as string, + accessor: ({ device }) => [device.model_id, device.definition?.model].join(' '), + Cell: ({ row: { original: { device } } }) => + }, + { + Header: () => , + id: 'check_all', + Cell: ({ row: { original: { device, state } } }) => + }, + ] return
- - - - - - - - - - - - - {otaDevices.length === 0 ? : null} - {otaDevices.map(device => ( - - ))} - -
{t("zigbee:friendly_name")}{t("zigbee:manufacturer")}{t("zigbee:model")}{t("zigbee:firmware_build_date")}{t("zigbee:firmware_version")}
{t('empty_ota_message')}
+ } diff --git a/src/components/zigbee/ReactTableCom.tsx b/src/components/zigbee/ReactTableCom.tsx deleted file mode 100644 index a3e7af403..000000000 --- a/src/components/zigbee/ReactTableCom.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import React from "react"; -import { useTable, useSortBy, HeaderGroup, Column, UseSortByOptions, UsePaginationOptions, useAsyncDebounce, useGlobalFilter } from 'react-table' -import { ZigbeeTableData as Data } from "."; -import cx from "classnames"; -import { useTranslation } from "react-i18next"; - -interface Props { - columns: Array>; - data: Array; -} - -function GlobalFilter({ - globalFilter, - setGlobalFilter, -}) { - const [value, setValue] = React.useState(globalFilter) - const onChange = useAsyncDebounce(value => { - setGlobalFilter(value || undefined) - }, 200); - - const { t } = useTranslation(['common']) - - return ( - - { - setValue(e.target.value); - onChange(e.target.value); - }} - placeholder={t('common:enter_search_criteria')} - className="form-control" - /> - - ) -} - -export const Table: React.FC = ({ columns, data }) => { - - const { - getTableProps, - getTableBodyProps, - headerGroups, - rows, - prepareRow, - state, - visibleColumns, - setGlobalFilter, - } = useTable( - { - columns, - data, - }, - useGlobalFilter, - useSortBy - ) - - - return ( - <> -
- - - - - {headerGroups.map((headerGroup: HeaderGroup) => ( - - {headerGroup.headers.map(column => ( - - ))} - - ))} - - - - {rows.map( - (row, i) => { - prepareRow(row); - return ( - - {row.cells.map(cell => )} - - ) - } - )} - -
- -
- {column.render('Header')} - - {column.isSorted - ? column.isSortedDesc - ? - : - : } - -
{cell.render('Cell')}
- - ) -} \ No newline at end of file diff --git a/src/components/zigbee/index.tsx b/src/components/zigbee/index.tsx index aa6fbc319..c1217f917 100644 --- a/src/components/zigbee/index.tsx +++ b/src/components/zigbee/index.tsx @@ -16,9 +16,9 @@ import { DisplayValue } from "../display-value/DisplayValue"; import { LastSeen } from "../LastSeen"; import PowerSource from "../power-source"; import DeviceControlGroup from "../device-control/DeviceControlGroup"; -import { Table } from "./ReactTableCom"; +import { Table } from "../grid/ReactTableCom"; import { CellProps, Column } from "react-table"; -import { join } from "lodash"; + type SortOrder = "asc" | "desc"; @@ -146,7 +146,7 @@ export class ZigbeeTable extends Component { const devices = this.getDevicesToRender(); const { sortColumnId, sortDirection, search } = this.state; const lastSeenType = getLastSeenType(bridgeInfo.config.advanced); - const reactTableColumns: Column[] = [ + const columns: Column[] = [ { Header: '#', id: '-rownumber', @@ -209,7 +209,7 @@ export class ZigbeeTable extends Component { return (