implemented column filtering in ResponsiveTable
This commit is contained in:
parent
4829e8d841
commit
1fb166650f
2 changed files with 60 additions and 35 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { Box, Card, CircularProgress, Collapse, darken, Divider, Grid2, IconButton, InputAdornment, ListItemButton, Paper, SxProps, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TextField, Theme, Typography } from "@mui/material";
|
||||
import { Box, Card, Checkbox, CircularProgress, Collapse, darken, Divider, Grid2, IconButton, InputAdornment, ListItemButton, ListItemIcon, ListItemText, Menu, MenuItem, Paper, SxProps, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow, TextField, Theme, Typography } from "@mui/material";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { ChevronRight, Close, Search } from "@mui/icons-material"
|
||||
import { ChevronRight, Close, Search, ViewColumn } from "@mui/icons-material"
|
||||
import { useEffect, useState } from "react";
|
||||
import React from "react";
|
||||
import { useMobile } from "hooks";
|
||||
|
|
@ -61,7 +61,7 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
);
|
||||
|
||||
export interface Column<T> {
|
||||
title: string | JSX.Element;
|
||||
title: string;
|
||||
cellStyle?: SxProps<Theme>;
|
||||
render: (row: T) => JSX.Element;
|
||||
}
|
||||
|
|
@ -117,6 +117,18 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
const [inputSearchText, setInputSearchText] = useState("");
|
||||
const [openGutters, setOpenGutters] = useState<number[]>([])
|
||||
const [handler, setHandler] = useState<NodeJS.Timeout | undefined>(undefined);
|
||||
const [columnAnchor, setColumnAnchor] = useState<any>(null)
|
||||
const [filterList, setFilterList] = useState<string[]>([])
|
||||
|
||||
const openColumnMenu = (event: any) => {
|
||||
setColumnAnchor(event.currentTarget);
|
||||
// setUserMenuIsOpen(true);
|
||||
};
|
||||
|
||||
const closeColumnMenu = () => {
|
||||
setColumnAnchor(null);
|
||||
// setUserMenuIsOpen(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!setSearchText) return;
|
||||
|
|
@ -266,12 +278,14 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
)
|
||||
}
|
||||
|
||||
|
||||
if (isMobile) return (
|
||||
<Box>
|
||||
<Box className={classes.mobileTitleBox}>
|
||||
{renderTitle()}
|
||||
{renderSubtitle()}
|
||||
{setSearchText && searchBar()}
|
||||
|
||||
</Box>
|
||||
{rows.map((row, index) => {
|
||||
return (
|
||||
|
|
@ -322,6 +336,17 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
</Box>
|
||||
)
|
||||
|
||||
const filter = (colName: string) => {
|
||||
let newFilterList = [...filterList]
|
||||
if (filterList.includes(colName)) {
|
||||
newFilterList = newFilterList.filter(name => name !== colName)
|
||||
} else {
|
||||
newFilterList.push(colName)
|
||||
}
|
||||
setFilterList(newFilterList)
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<TableContainer className={classes.tableContainer} component={Paper}>
|
||||
<Table>
|
||||
|
|
@ -345,6 +370,13 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
{searchBar()}
|
||||
</Box>}
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
{ columns &&
|
||||
<IconButton onClick={openColumnMenu} >
|
||||
<ViewColumn />
|
||||
</IconButton>
|
||||
}
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
|
|
@ -354,6 +386,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
{ renderGutter && <TableCell></TableCell>}
|
||||
{ columns ?
|
||||
columns.map((column, index) => {
|
||||
if (filterList.includes(column.title)) return null
|
||||
return (
|
||||
<TableCell key={"header-cell-"+index}>
|
||||
{column.title}
|
||||
|
|
@ -382,6 +415,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
</TableRow>
|
||||
:
|
||||
rows.map((row, index) => {
|
||||
// if (filterList.includes()) return null
|
||||
return (
|
||||
<React.Fragment key={"row-"+index}>
|
||||
<TableRow onClick={() => onRowClick&&onRowClick(row)} className={onRowClick ? classes.rowHover : undefined}>
|
||||
|
|
@ -400,6 +434,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
}
|
||||
{columns ?
|
||||
columns.map((column, j) => {
|
||||
if (filterList.includes(column.title)) return null
|
||||
if (column.render) return (
|
||||
<TableCell key={"row-"+index+"cell-"+j} sx={{ padding: 0}} >
|
||||
{column.render(row)}
|
||||
|
|
@ -454,6 +489,26 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
onPageChange={(_event, page) => handlePageChange(page)}
|
||||
onRowsPerPageChange={handleRowsPerPageChange}
|
||||
/>
|
||||
<Menu
|
||||
id="userMenu"
|
||||
anchorEl={columnAnchor}
|
||||
open={columnAnchor !== null}
|
||||
onClose={closeColumnMenu}
|
||||
disableAutoFocusItem>
|
||||
{columns?.map((column, index) => {
|
||||
return (
|
||||
<MenuItem key={"column-list-"+index} aria-label="Open User Settings" dense sx={{ marginLeft: -0.75 }}>
|
||||
<ListItemIcon>
|
||||
<Checkbox
|
||||
checked={!filterList.includes(column.title)}
|
||||
onClick={() => filter(column.title)}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={column.title} />
|
||||
</MenuItem>
|
||||
)
|
||||
})}
|
||||
</Menu>
|
||||
</TableContainer>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { DeveloperBoard as ProvisionIcon, LibraryAdd as CreateGroupIcon } from "@mui/icons-material";
|
||||
import { Box, Chip, CircularProgress, Grid2, IconButton, Skeleton, Tab, Tabs, Theme, Tooltip, Typography } from "@mui/material";
|
||||
import { Box, Chip, Grid2, IconButton, Skeleton, Tab, Tabs, Theme, Tooltip, Typography } from "@mui/material";
|
||||
import { blue, green, orange } from "@mui/material/colors";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||
|
|
@ -8,7 +8,7 @@ import { pond } from "protobuf-ts/pond";
|
|||
import { useDeviceAPI, useGroupAPI } from "providers";
|
||||
import { useEffect, useState } from "react";
|
||||
import PageContainer from "./PageContainer";
|
||||
import { useMobile, usePermissionAPI } from "hooks";
|
||||
import { useMobile } from "hooks";
|
||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||
import { getDeviceStateHelper } from "pbHelpers/DeviceState";
|
||||
|
|
@ -18,7 +18,6 @@ import SmartBreadcrumb from "common/SmartBreadcrumb";
|
|||
import GroupActions from "group/GroupActions";
|
||||
// import CircleGraphIcon from "common/CircleGraphIcon";
|
||||
import DevicesSummary from "device/DevicesSummary";
|
||||
import MeasurementSummary from "component/MeasurementSummary";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
|
|
@ -76,7 +75,6 @@ export default function Devices() {
|
|||
const location = useLocation();
|
||||
const deviceAPI = useDeviceAPI();
|
||||
const groupAPI = useGroupAPI();
|
||||
const permissionAPI = usePermissionAPI();
|
||||
const [devicesLoading, setDevicesLoading] = useState(false)
|
||||
const [limit, setLimit] = useState(10);
|
||||
const [page, setPage] = useState(0);
|
||||
|
|
@ -86,8 +84,6 @@ export default function Devices() {
|
|||
const [total, setTotal] = useState(0);
|
||||
const [devices, setDevices] = useState<Device[]>([])
|
||||
const [isProvisionDialogOpen, setIsProvisionDialogOpen] = useState<boolean>(false);
|
||||
const [stats, setStats] = useState<pond.DeviceStatistics>(pond.DeviceStatistics.create())
|
||||
const [loadingStats, setLoadingStats] = useState(false)
|
||||
const [hasPlenums, setHasPlenums] = useState(false)
|
||||
|
||||
const [groupsLoading, setGroupsLoading] = useState(false)
|
||||
|
|
@ -218,44 +214,18 @@ export default function Devices() {
|
|||
})
|
||||
}
|
||||
|
||||
const loadDeviceStatistics = () => {
|
||||
setLoadingStats(true)
|
||||
deviceAPI.statistics(
|
||||
getContextKeys(),
|
||||
getContextTypes()
|
||||
).then(resp => {
|
||||
let stats = pond.DeviceStatistics.fromObject(resp.data.stats)
|
||||
setStats(stats)
|
||||
}).finally(() => {
|
||||
setLoadingStats(false)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadDevices()
|
||||
}, [limit, page, order, orderBy, search, tab])
|
||||
|
||||
useEffect(() => {
|
||||
loadDeviceStatistics()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
loadGroups()
|
||||
}, [groupLimit, groupPage, orderGroup, orderGroupBy, searchGroup])
|
||||
|
||||
// useEffect(() => {
|
||||
// permissionAPI.getPermissions
|
||||
// }, [groupID])
|
||||
|
||||
const handleChange = (event: any) => {
|
||||
setLimit(event.target.value);
|
||||
};
|
||||
|
||||
// const appendToUrl = (appendage: number | string) => {
|
||||
// const basePath = location.pathname.replace(/\/$/, "");
|
||||
// return(`${basePath}/${appendage}`);
|
||||
// };
|
||||
|
||||
const prependToUrl = (prependage: number | string) => {
|
||||
const basePath = location.pathname.replace(/\/$/, "");
|
||||
return(`/${prependage}/${basePath}`.replace(/\/{2,}/g, "/").replace(/(\/[^/]+)\/\1+/g, "$1"));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue