15951: Makes 'mutually exclusive' filter dialog auto-submit selection on click.
[arvados-workbench2.git] / src / components / data-table-filters / data-table-filters-tree.tsx
index 3ce4dbbefc41b28bb66a8a5cabe7d26625ca48df..be08743eefa507768de0570debebaabbd0fc8887 100644 (file)
@@ -3,10 +3,11 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from "react";
-import { Tree, toggleNodeSelection, getNode, initTreeNode, getNodeChildrenIds } from '~/models/tree';
+import { Tree, toggleNodeSelection, getNode, initTreeNode, getNodeChildrenIds, selectNode, deselectNodes } from '~/models/tree';
 import { Tree as TreeComponent, TreeItem, TreeItemStatus } from '~/components/tree/tree';
 import { noop, map } from "lodash/fp";
 import { toggleNodeCollapse } from '~/models/tree';
+import { countNodes, countChildren } from '~/models/tree';
 
 export interface DataTableFilterItem {
     name: string;
@@ -17,24 +18,47 @@ export type DataTableFilters = Tree<DataTableFilterItem>;
 export interface DataTableFilterProps {
     filters: DataTableFilters;
     onChange?: (filters: DataTableFilters) => void;
+
+    /**
+     * When set to true, only one filter can be selected at a time.
+     */
+    mutuallyExclusive?: boolean;
 }
 
 export class DataTableFiltersTree extends React.Component<DataTableFilterProps> {
 
     render() {
+        const { filters } = this.props;
+        const hasSubfilters = countNodes(filters) !== countChildren('')(filters);
         return <TreeComponent
-            items={filtersToTree(this.props.filters)}
+            levelIndentation={hasSubfilters ? 20 : 0}
+            itemRightPadding={20}
+            items={filtersToTree(filters)}
             render={renderItem}
             showSelection
+            useRadioButtons={this.props.mutuallyExclusive}
+            disableRipple
             onContextMenu={noop}
-            toggleItemActive={noop}
+            toggleItemActive={this.props.mutuallyExclusive ? this.toggleRadioButtonFilter : noop}
             toggleItemOpen={this.toggleOpen}
             toggleItemSelection={this.toggleFilter}
         />;
     }
 
-    renderItem(item: TreeItem<DataTableFilterItem>) {
-        return <span>{item.data.name}</span>;
+    /**
+     * Handler for when a tree item is toggled via a radio button.
+     * Ensures mutual exclusivity among filter tree items.
+     */
+    toggleRadioButtonFilter = (_: any, item: TreeItem<DataTableFilterItem>) => {
+        const { onChange = noop } = this.props;
+
+        // If the filter is already selected, do nothing.
+        if (item.selected) { return; }
+
+        // Otherwise select this node and deselect the others
+        const filters = selectNode(item.id)(this.props.filters);
+        const toDeselect = Object.keys(this.props.filters).filter((id) => (id !== item.id));
+        onChange(deselectNodes(toDeselect)(filters));
     }
 
     toggleFilter = (_: React.MouseEvent, item: TreeItem<DataTableFilterItem>) => {