X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/57963d0ef4a73cc7222f93e61cb7bcf8cffc3f75..58800bbe6e474679dcfbc03735541a578280dd85:/src/components/data-table-filters/data-table-filters-popover.tsx diff --git a/src/components/data-table-filters/data-table-filters-popover.tsx b/src/components/data-table-filters/data-table-filters-popover.tsx index 9da3c20c..b5187866 100644 --- a/src/components/data-table-filters/data-table-filters-popover.tsx +++ b/src/components/data-table-filters/data-table-filters-popover.tsx @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0 -import * as React from "react"; +import React, { useEffect } from "react"; import { WithStyles, withStyles, @@ -15,15 +15,17 @@ import { CardActions, Typography, CardContent, - Tooltip + Tooltip, + IconButton } from "@material-ui/core"; -import * as classnames from "classnames"; -import { DefaultTransformOrigin } from "~/components/popover/helpers"; -import { createTree } from '~/models/tree'; +import classnames from "classnames"; +import { DefaultTransformOrigin } from "components/popover/helpers"; +import { createTree } from 'models/tree'; import { DataTableFilters, DataTableFiltersTree } from "./data-table-filters-tree"; -import { getNodeDescendants } from '~/models/tree'; +import { getNodeDescendants } from 'models/tree'; +import debounce from "lodash/debounce"; -export type CssRules = "root" | "icon" | "active" | "checkbox"; +export type CssRules = "root" | "icon" | "iconButton" | "active" | "checkbox"; const styles: StyleRulesCallback = (theme: Theme) => ({ root: { @@ -41,16 +43,20 @@ const styles: StyleRulesCallback = (theme: Theme) => ({ }, active: { color: theme.palette.text.primary, - '& $icon': { + '& $iconButton': { opacity: 1, }, }, icon: { - marginRight: 4, - marginLeft: 4, + fontSize: 12, + userSelect: 'none', + width: 16, + height: 15, + marginTop: 1 + }, + iconButton: { + color: theme.palette.text.primary, opacity: 0.7, - userSelect: "none", - width: 16 }, checkbox: { width: 24, @@ -68,6 +74,11 @@ export interface DataTableFilterProps { filters: DataTableFilters; onChange?: (filters: DataTableFilters) => void; + /** + * When set to true, only one filter can be selected at a time. + */ + mutuallyExclusive?: boolean; + /** * By default `all` filters selection means that label should be grayed out. * Use `none` when label is supposed to be grayed out when no filter is selected. @@ -98,16 +109,18 @@ export const DataTableFiltersPopover = withStyles(styles)( : f.selected ); return <> - + {children} - + + + + onClose={this.close}> @@ -124,25 +137,22 @@ export const DataTableFiltersPopover = withStyles(styles)( this.setState({ filters })} /> + mutuallyExclusive={this.props.mutuallyExclusive} + onChange={this.onChange} /> + {this.props.mutuallyExclusive || - + } + ; } @@ -156,25 +166,43 @@ export const DataTableFiltersPopover = withStyles(styles)( this.setState({ anchorEl: this.icon.current || undefined }); } - submit = () => { + onChange = (filters) => { + this.setState({ filters }); + if (this.props.mutuallyExclusive) { + // Mutually exclusive filters apply immediately + const { onChange } = this.props; + if (onChange) { + onChange(filters); + } + this.close(); + } else { + // Non-mutually exclusive filters are debounced + this.submit(); + } + } + + submit = debounce (() => { const { onChange } = this.props; if (onChange) { onChange(this.state.filters); } - this.setState({ anchorEl: undefined }); - } + }, 1000); - cancel = () => { + MountHandler = () => { + useEffect(() => { + return () => { + this.submit.cancel(); + } + },[]); + return null; + }; + + close = () => { this.setState(prev => ({ ...prev, - filters: prev.prevFilters, anchorEl: undefined })); } - setFilters = (filters: DataTableFilters) => { - this.setState({ filters }); - } - } );