6a38581e2de507da42a86b391bf73ea6c35305bc
[arvados.git] / src / components / data-table-multiselect-popover / data-table-multiselect-popover.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React, { useEffect } from 'react';
6 import { WithStyles, withStyles, ButtonBase, StyleRulesCallback, Theme, Popover, Card, Tooltip, IconButton } from '@material-ui/core';
7 import classnames from 'classnames';
8 import { DefaultTransformOrigin } from 'components/popover/helpers';
9 import debounce from 'lodash/debounce';
10 import { grey } from '@material-ui/core/colors';
11 import { TCheckedList } from 'components/data-table/data-table';
12
13 export type CssRules = 'root' | 'icon' | 'iconButton' | 'disabled' | 'optionsContainer' | 'option';
14
15 const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
16     root: {
17         borderRadius: '7px',
18         '&:hover': {
19             backgroundColor: grey[200],
20         },
21         '&:focus': {
22             color: theme.palette.text.primary,
23         },
24     },
25     icon: {
26         cursor: 'pointer',
27         fontSize: 20,
28         userSelect: 'none',
29         '&:hover': {
30             color: theme.palette.text.primary,
31         },
32         paddingBottom: '5px',
33     },
34     iconButton: {
35         color: theme.palette.text.primary,
36         opacity: 0.6,
37         padding: 1,
38         paddingBottom: 5,
39     },
40     disabled: {
41         color: grey[500],
42     },
43     optionsContainer: {
44         padding: '1rem 0',
45         flex: 1,
46     },
47     option: {
48         cursor: 'pointer',
49         display: 'flex',
50         padding: '3px 2rem',
51         fontSize: '0.9rem',
52         alignItems: 'center',
53         '&:hover': {
54             backgroundColor: 'rgba(0, 0, 0, 0.08)',
55         },
56     },
57 });
58
59 export type DataTableMultiselectOption = {
60     name: string;
61     fn: (checkedList) => void;
62 };
63
64 export interface DataTableMultiselectProps {
65     name: string;
66     disabled: boolean;
67     options: DataTableMultiselectOption[];
68     checkedList: TCheckedList;
69 }
70
71 interface DataTableFMultiselectPopState {
72     anchorEl?: HTMLElement;
73 }
74
75 export const DataTableMultiselectPopover = withStyles(styles)(
76     class extends React.Component<DataTableMultiselectProps & WithStyles<CssRules>, DataTableFMultiselectPopState> {
77         state: DataTableFMultiselectPopState = {
78             anchorEl: undefined,
79         };
80         icon = React.createRef<HTMLElement>();
81
82         render() {
83             const { classes, children, options, checkedList, disabled } = this.props;
84             return (
85                 <>
86                     <Tooltip disableFocusListener title='Select Options'>
87                         <ButtonBase className={classnames(classes.root)} component='span' onClick={disabled ? () => {} : this.open} disableRipple>
88                             {children}
89                             <IconButton component='span' classes={{ root: classes.iconButton }} tabIndex={-1}>
90                                 <i
91                                     className={`${classnames(['fas fa-sort-down', classes.icon])}${disabled ? ` ${classes.disabled}` : ''}`}
92                                     data-fa-transform='shrink-3'
93                                     ref={this.icon}
94                                 />
95                             </IconButton>
96                         </ButtonBase>
97                     </Tooltip>
98                     <Popover
99                         anchorEl={this.state.anchorEl}
100                         open={!!this.state.anchorEl}
101                         anchorOrigin={DefaultTransformOrigin}
102                         transformOrigin={DefaultTransformOrigin}
103                         onClose={this.close}
104                     >
105                         <Card>
106                             <div className={classes.optionsContainer}>
107                                 {options.length &&
108                                     options.map((option, i) => (
109                                         <div
110                                             key={i}
111                                             className={classes.option}
112                                             onClick={() => {
113                                                 option.fn(checkedList);
114                                                 this.close();
115                                             }}
116                                         >
117                                             {option.name}
118                                         </div>
119                                     ))}
120                             </div>
121                         </Card>
122                     </Popover>
123                     <this.MountHandler />
124                 </>
125             );
126         }
127
128         open = () => {
129             this.setState({ anchorEl: this.icon.current || undefined });
130         };
131
132         submit = debounce(() => {
133             // const { onChange } = this.props;
134             // if (onChange) {
135             //     onChange(this.state.filters);
136             // }
137         }, 1000);
138
139         MountHandler = () => {
140             useEffect(() => {
141                 return () => {
142                     this.submit.cancel();
143                 };
144             }, []);
145             return null;
146         };
147
148         close = () => {
149             this.setState((prev) => ({
150                 ...prev,
151                 anchorEl: undefined,
152             }));
153         };
154     }
155 );