X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/4ff3ff000c1a0132d29ea4829907f484467b6275..cfe5ff035578ede95613b0c545708466da78cbea:/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 7033d369..3183157b 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 from "react"; import { WithStyles, withStyles, @@ -10,25 +10,21 @@ import { StyleRulesCallback, Theme, Popover, - List, - ListItem, - Checkbox, - ListItemText, Button, Card, CardActions, Typography, CardContent, - Tooltip + Tooltip, + IconButton } from "@material-ui/core"; -import * as classnames from "classnames"; -import { DefaultTransformOrigin } from "../popover/helpers"; -import { createTree, initTreeNode, mapTree } from '~/models/tree'; -import { DataTableFilters as DataTableFiltersModel, DataTableFiltersTree } from "./data-table-filters-tree"; -import { pipe } from 'lodash/fp'; -import { setNode } 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'; -export type CssRules = "root" | "icon" | "active" | "checkbox"; +export type CssRules = "root" | "icon" | "iconButton" | "active" | "checkbox"; const styles: StyleRulesCallback = (theme: Theme) => ({ root: { @@ -46,16 +42,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, @@ -63,59 +63,63 @@ const styles: StyleRulesCallback = (theme: Theme) => ({ } }); -export interface DataTableFilterItem { - name: string; - selected: boolean; +enum SelectionMode { + ALL = 'all', + NONE = 'none' } export interface DataTableFilterProps { name: string; - filters: DataTableFilterItem[]; - onChange?: (filters: DataTableFilterItem[]) => void; + 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. + */ + defaultSelection?: SelectionMode; } interface DataTableFilterState { anchorEl?: HTMLElement; - filters: DataTableFilterItem[]; - prevFilters: DataTableFilterItem[]; - filtersTree: DataTableFiltersModel; + filters: DataTableFilters; + prevFilters: DataTableFilters; } -const filters: DataTableFiltersModel = pipe( - createTree, - setNode(initTreeNode({ id: 'Project', value: { name: 'Project' } })), - setNode(initTreeNode({ id: 'Process', value: { name: 'Process' } })), - setNode(initTreeNode({ id: 'Data collection', value: { name: 'Data collection' } })), - setNode(initTreeNode({ id: 'General', parent: 'Data collection', value: { name: 'General' } })), - setNode(initTreeNode({ id: 'Output', parent: 'Data collection', value: { name: 'Output' } })), - setNode(initTreeNode({ id: 'Log', parent: 'Data collection', value: { name: 'Log' } })), - mapTree(node => ({...node, selected: true})), -)(); - -export const DataTableFilters = withStyles(styles)( +export const DataTableFiltersPopover = withStyles(styles)( class extends React.Component, DataTableFilterState> { state: DataTableFilterState = { anchorEl: undefined, - filters: [], - prevFilters: [], - filtersTree: filters, + filters: createTree(), + prevFilters: createTree(), }; icon = React.createRef(); render() { - const { name, classes, children } = this.props; - const isActive = this.state.filters.some(f => f.selected); + 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} - + + + - - {this.state.filters.map((filter, index) => - - - - {filter.name} - - - )} - this.setState({ filtersTree })} /> + filters={this.state.filters} + mutuallyExclusive={this.props.mutuallyExclusive} + onChange={filters => { + this.setState({ filters }); + if (this.props.mutuallyExclusive) { + const { onChange } = this.props; + if (onChange) { + onChange(filters); + } + this.setState({ anchorEl: undefined }); + } + }} /> + {this.props.mutuallyExclusive || + } ; @@ -195,14 +196,9 @@ export const DataTableFilters = withStyles(styles)( })); } - toggleFilter = (toggledFilter: DataTableFilterItem) => () => { - this.setState(prev => ({ - ...prev, - filters: prev.filters.map(filter => - filter === toggledFilter - ? { ...filter, selected: !filter.selected } - : filter) - })); + setFilters = (filters: DataTableFilters) => { + this.setState({ filters }); } + } );