toolbar selects for appropriate buttons, just not very well Arvados-DCO-1.1-Signed...
[arvados.git] / src / components / multiselectToolbar / MultiselectToolbar.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React, { ReactElement } from 'react';
6 import { connect } from 'react-redux';
7 import { StyleRulesCallback, withStyles, WithStyles, Toolbar, Button } from '@material-ui/core';
8 import { ArvadosTheme } from 'common/custom-theme';
9 import { RootState } from 'store/store';
10 import { Dispatch } from 'redux';
11 import { CopyToClipboardSnackbar } from 'components/copy-to-clipboard-snackbar/copy-to-clipboard-snackbar';
12 import { TCheckedList } from 'components/data-table/data-table';
13 import { openRemoveProcessDialog, openRemoveManyProcessesDialog } from 'store/processes/processes-actions';
14 import { processResourceActionSet } from '../../views-components/context-menu/action-sets/process-resource-action-set';
15 import { ContextMenuResource } from 'store/context-menu/context-menu-actions';
16 import { toggleTrashed } from 'store/trash/trash-actions';
17 import { ResourceKind, extractUuidKind } from 'models/resource';
18
19 type CssRules = 'root' | 'expanded' | 'button';
20
21 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
22     root: {
23         display: 'flex',
24         flexDirection: 'row',
25         width: 0,
26         padding: 0,
27         margin: '1rem auto auto 0.5rem',
28         overflow: 'hidden',
29     },
30     expanded: {
31         transition: 'width 150ms',
32         transitionTimingFunction: 'ease-in',
33     },
34     button: {
35         backgroundColor: '#017ead',
36         color: 'white',
37         fontSize: '0.75rem',
38         width: 'auto',
39         margin: 'auto',
40         padding: '1px',
41     },
42 });
43
44 type MultiselectToolbarAction = {
45     name: string;
46     action: string;
47     relevantKinds: Array<ResourceKind>;
48 };
49
50 export const defaultActions: Array<MultiselectToolbarAction> = [
51     {
52         name: 'copy',
53         action: 'copySelected',
54         relevantKinds: [ResourceKind.COLLECTION],
55     },
56     {
57         name: 'move',
58         action: 'moveSelected',
59         relevantKinds: [ResourceKind.COLLECTION, ResourceKind.PROCESS],
60     },
61     {
62         name: 'remove',
63         action: 'removeSelected',
64         relevantKinds: [ResourceKind.COLLECTION],
65     },
66 ];
67
68 export type MultiselectToolbarProps = {
69     actions: Array<MultiselectToolbarAction>;
70     isVisible: boolean;
71     checkedList: TCheckedList;
72     copySelected: () => void;
73     moveSelected: () => void;
74     removeSelected: (selectedList: TCheckedList) => void;
75 };
76
77 export const MultiselectToolbar = connect(
78     mapStateToProps,
79     mapDispatchToProps
80 )(
81     withStyles(styles)((props: MultiselectToolbarProps & WithStyles<CssRules>) => {
82         // console.log(props);
83         const { classes, actions, isVisible, checkedList } = props;
84
85         //include any action that can be applied to all selected elements
86
87         const currentResourceKinds = new Set(selectedToArray(checkedList).map((element) => extractUuidKind(element) as string));
88         console.log('CURRENT_KINDS', currentResourceKinds);
89         const buttons = actions.filter((action) => {
90             // console.log('ACTION.KINDS', action.relevantKinds);
91             return action.relevantKinds.every((kind) => {
92                 // console.log('KIND', kind);
93                 // console.log('setHasKind', currentResourceKinds.has(kind));
94                 return currentResourceKinds.has(kind);
95             });
96         });
97         // console.log('BUTTONS', buttons);
98         return (
99             <Toolbar className={isVisible && buttons.length ? `${classes.root} ${classes.expanded}` : classes.root} style={{ width: `${buttons.length * 5.8}rem` }}>
100                 {buttons.length ? (
101                     buttons.map((btn) => (
102                         <Button key={btn.name} className={`${classes.button} ${classes.expanded}`} onClick={() => props[btn.action](checkedList)}>
103                             {btn.name}
104                         </Button>
105                     ))
106                 ) : (
107                     <></>
108                 )}
109             </Toolbar>
110         );
111     })
112 );
113
114 function selectedToString(checkedList: TCheckedList) {
115     let stringifiedSelectedList: string = '';
116     for (const [key, value] of Object.entries(checkedList)) {
117         if (value === true) {
118             stringifiedSelectedList += key + ',';
119         }
120     }
121     return stringifiedSelectedList.slice(0, -1);
122 }
123
124 function selectedToArray<T>(checkedList: TCheckedList): Array<string> {
125     const arrayifiedSelectedList: Array<string> = [];
126     for (const [key, value] of Object.entries(checkedList)) {
127         if (value === true) {
128             arrayifiedSelectedList.push(key);
129         }
130     }
131     return arrayifiedSelectedList;
132 }
133
134 function mapStateToProps(state: RootState) {
135     // console.log(state.resources, state.multiselect.checkedList);
136     const { isVisible, checkedList } = state.multiselect;
137     return {
138         isVisible: isVisible,
139         checkedList: checkedList as TCheckedList,
140         // selectedList: state.multiselect.checkedList.forEach(processUUID=>containerRequestUUID)
141     };
142 }
143
144 function mapDispatchToProps(dispatch: Dispatch) {
145     return {
146         copySelected: () => {},
147         moveSelected: () => {},
148         removeSelected: (checkedList: TCheckedList) => removeMulti(dispatch, checkedList),
149     };
150 }
151
152 function removeMulti(dispatch: Dispatch, checkedList: TCheckedList): void {
153     const list: Array<string> = selectedToArray(checkedList);
154     dispatch<any>(list.length === 1 ? openRemoveProcessDialog(list[0]) : openRemoveManyProcessesDialog(list));
155 }