X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/76cc719bbb330ab23759c090a28c4c178d953436..f7a4118c87ae1df4a42efdad3695e6fcb5d60854:/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 456d2375..557abd82 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, @@ -16,27 +16,28 @@ import { Typography, CardContent, Tooltip, - IconButton -} from "@material-ui/core"; -import * as 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'; + IconButton, +} from '@material-ui/core'; +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 debounce from 'lodash/debounce'; -export type CssRules = "root" | "icon" | "iconButton" | "active" | "checkbox"; +export type CssRules = 'root' | 'icon' | 'iconButton' | 'active' | 'checkbox'; const styles: StyleRulesCallback = (theme: Theme) => ({ root: { - cursor: "pointer", - display: "inline-flex", - justifyContent: "flex-start", - flexDirection: "inherit", - alignItems: "center", - "&:hover": { + cursor: 'pointer', + display: 'inline-flex', + justifyContent: 'flex-start', + flexDirection: 'inherit', + alignItems: 'center', + '&:hover': { color: theme.palette.text.primary, }, - "&:focus": { + '&:focus': { color: theme.palette.text.primary, }, }, @@ -51,7 +52,7 @@ const styles: StyleRulesCallback = (theme: Theme) => ({ userSelect: 'none', width: 16, height: 15, - marginTop: 1 + marginTop: 1, }, iconButton: { color: theme.palette.text.primary, @@ -59,13 +60,13 @@ const styles: StyleRulesCallback = (theme: Theme) => ({ }, checkbox: { width: 24, - height: 24 - } + height: 24, + }, }); enum SelectionMode { ALL = 'all', - NONE = 'none' + NONE = 'none', } export interface DataTableFilterProps { @@ -102,103 +103,89 @@ export const DataTableFiltersPopover = withStyles(styles)( render() { const { name, classes, defaultSelection = SelectionMode.ALL, children } = this.props; - const isActive = getNodeDescendants('')(this.state.filters) - .some(f => defaultSelection === SelectionMode.ALL - ? !f.selected - : f.selected - ); - return <> - - - {children} - - - - - - - - - - {name} - - - { - this.setState({ filters }); - if (this.props.mutuallyExclusive) { - const { onChange } = this.props; - if (onChange) { - onChange(filters); - } - this.setState({ anchorEl: undefined }); - } - }} /> - {this.props.mutuallyExclusive || - - - - - } - - - ; + const isActive = getNodeDescendants('')(this.state.filters).some((f) => (defaultSelection === SelectionMode.ALL ? !f.selected : f.selected)); + return ( + <> + + + {children} + + + + + + + + + {name} + + + <> + {this.props.mutuallyExclusive || ( + + + + )} + + + + + + ); } static getDerivedStateFromProps(props: DataTableFilterProps, state: DataTableFilterState): DataTableFilterState { - return props.filters !== state.prevFilters - ? { ...state, filters: props.filters, prevFilters: props.filters } - : state; + return props.filters !== state.prevFilters ? { ...state, filters: props.filters, prevFilters: props.filters } : state; } open = () => { this.setState({ anchorEl: this.icon.current || undefined }); - } + }; + + 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 = () => { + submit = debounce(() => { const { onChange } = this.props; if (onChange) { onChange(this.state.filters); } - this.setState({ anchorEl: undefined }); - } + }, 1000); + + MountHandler = () => { + useEffect(() => { + return () => { + this.submit.cancel(); + }; + }, []); + return null; + }; - cancel = () => { - this.setState(prev => ({ + close = () => { + this.setState((prev) => ({ ...prev, - filters: prev.prevFilters, - anchorEl: undefined + anchorEl: undefined, })); - } - - setFilters = (filters: DataTableFilters) => { - this.setState({ filters }); - } - + }; } );