1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import * as React from "react";
20 } from "@material-ui/core";
21 import * as classnames from "classnames";
22 import { DefaultTransformOrigin } from "~/components/popover/helpers";
23 import { createTree } from '~/models/tree';
24 import { DataTableFilters, DataTableFiltersTree } from "./data-table-filters-tree";
25 import { getNodeDescendants } from '~/models/tree';
27 export type CssRules = "root" | "icon" | "iconButton" | "active" | "checkbox";
29 const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
32 display: "inline-flex",
33 justifyContent: "flex-start",
34 flexDirection: "inherit",
37 color: theme.palette.text.primary,
40 color: theme.palette.text.primary,
44 color: theme.palette.text.primary,
57 color: theme.palette.text.primary,
71 export interface DataTableFilterProps {
73 filters: DataTableFilters;
74 onChange?: (filters: DataTableFilters) => void;
77 * By default `all` filters selection means that label should be grayed out.
78 * Use `none` when label is supposed to be grayed out when no filter is selected.
80 defaultSelection?: SelectionMode;
83 interface DataTableFilterState {
84 anchorEl?: HTMLElement;
85 filters: DataTableFilters;
86 prevFilters: DataTableFilters;
89 export const DataTableFiltersPopover = withStyles(styles)(
90 class extends React.Component<DataTableFilterProps & WithStyles<CssRules>, DataTableFilterState> {
91 state: DataTableFilterState = {
93 filters: createTree(),
94 prevFilters: createTree(),
96 icon = React.createRef<HTMLElement>();
99 const { name, classes, defaultSelection = SelectionMode.ALL, children } = this.props;
100 const isActive = getNodeDescendants('')(this.state.filters)
101 .some(f => defaultSelection === SelectionMode.ALL
106 <Tooltip title='Filters'>
108 className={classnames([classes.root, { [classes.active]: isActive }])}
113 <IconButton component='span' classes={{root: classes.iconButton}} tabIndex={-1}>
114 <i className={classnames(["fas fa-filter", classes.icon])}
115 data-fa-transform="shrink-3"
121 anchorEl={this.state.anchorEl}
122 open={!!this.state.anchorEl}
123 anchorOrigin={DefaultTransformOrigin}
124 transformOrigin={DefaultTransformOrigin}
125 onClose={this.cancel}>
128 <Typography variant="caption">
132 <DataTableFiltersTree
133 filters={this.state.filters}
134 onChange={filters => this.setState({ filters })} />
140 onClick={this.submit}>
147 onClick={this.cancel}>
156 static getDerivedStateFromProps(props: DataTableFilterProps, state: DataTableFilterState): DataTableFilterState {
157 return props.filters !== state.prevFilters
158 ? { ...state, filters: props.filters, prevFilters: props.filters }
163 this.setState({ anchorEl: this.icon.current || undefined });
167 const { onChange } = this.props;
169 onChange(this.state.filters);
171 this.setState({ anchorEl: undefined });
175 this.setState(prev => ({
177 filters: prev.prevFilters,
182 setFilters = (filters: DataTableFilters) => {
183 this.setState({ filters });