X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/27542ce48fa48c5bbe16e96a3ffd1cea0be0cc47..4ef379e48ed887a2c6f5eeeb84753bd0ec68c124:/src/components/multiselectToolbar/MultiselectToolbar.tsx?ds=sidebyside diff --git a/src/components/multiselectToolbar/MultiselectToolbar.tsx b/src/components/multiselectToolbar/MultiselectToolbar.tsx index ea00860d26..085174dd14 100644 --- a/src/components/multiselectToolbar/MultiselectToolbar.tsx +++ b/src/components/multiselectToolbar/MultiselectToolbar.tsx @@ -2,60 +2,213 @@ // // SPDX-License-Identifier: AGPL-3.0 -import React from 'react'; -import { connect } from 'react-redux'; -import { StyleRulesCallback, withStyles, WithStyles, Toolbar, Button } from '@material-ui/core'; -import { ArvadosTheme } from 'common/custom-theme'; -import { RootState } from 'store/store'; +import React from "react"; +import { connect } from "react-redux"; +import { StyleRulesCallback, withStyles, WithStyles, Toolbar, Tooltip, IconButton } from "@material-ui/core"; +import { ArvadosTheme } from "common/custom-theme"; +import { RootState } from "store/store"; +import { Dispatch } from "redux"; +import { TCheckedList } from "components/data-table/data-table"; +import { ContextMenuResource } from "store/context-menu/context-menu-actions"; +import { Resource, extractUuidKind } from "models/resource"; +import { getResource } from "store/resources/resources"; +import { ResourcesState } from "store/resources/resources"; +import { ContextMenuAction, ContextMenuActionSet } from "views-components/context-menu/context-menu-action-set"; +import { RestoreFromTrashIcon, TrashIcon } from "components/icon/icon"; +import { multiselectActionsFilters, TMultiselectActionsFilters, contextMenuActionConsts } from "./ms-toolbar-action-filters"; +import { kindToActionSet, findActionByName } from "./ms-kind-action-differentiator"; +import { toggleTrashAction } from "views-components/context-menu/action-sets/project-action-set"; +import { copyToClipboardAction } from "store/open-in-new-tab/open-in-new-tab.actions"; -type CssRules = 'root' | 'item'; +type CssRules = "root" | "button"; const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ root: { - display: 'flex', - flexDirection: 'row', + display: "flex", + flexDirection: "row", + width: 0, + padding: 0, + margin: "1rem auto auto 0.5rem", + overflow: "hidden", + transition: "width 150ms", }, - item: { - color: theme.palette.text.primary, - margin: '0.5rem', + button: { + width: "1rem", + margin: "auto 5px", }, }); -type MultiselectToolbarAction = { - name: string; - fn: () => void; +export type MultiselectToolbarProps = { + isVisible: boolean; + checkedList: TCheckedList; + resources: ResourcesState; + executeMulti: (action: ContextMenuAction, checkedList: TCheckedList, resources: ResourcesState) => void; }; -export type MultiselectToolbarActions = { - actions: Array; -}; - -export const defaultActions: Array = [ - { - name: 'foo', - fn: () => console.log('yo'), - }, -]; +export const MultiselectToolbar = connect( + mapStateToProps, + mapDispatchToProps +)( + withStyles(styles)((props: MultiselectToolbarProps & WithStyles) => { + const { classes, checkedList } = props; + const currentResourceKinds = Array.from(selectedToKindSet(checkedList)); -type MultiselectToolbarProps = MultiselectToolbarActions & WithStyles; + const currentPathIsTrash = window.location.pathname === "/trash"; + const buttons = + currentPathIsTrash && selectedToKindSet(checkedList).size + ? [toggleTrashAction] + : selectActionsByKind(currentResourceKinds, multiselectActionsFilters); -export const MultiselectToolbar = connect(mapStateToProps)( - withStyles(styles)((props: MultiselectToolbarProps) => { - const { classes, actions } = props; return ( - - {actions.map((action, i) => ( - - ))} + + {buttons.length ? ( + buttons.map((btn, i) => + btn.name === "ToggleTrashAction" ? ( + + props.executeMulti(btn, checkedList, props.resources)}> + {currentPathIsTrash ? : } + + + ) : ( + + props.executeMulti(btn, checkedList, props.resources)}> + {btn.icon ? btn.icon({}) : <>} + + + ) + ) + ) : ( + <> + )} ); }) ); +export function selectedToArray(checkedList: TCheckedList): Array { + const arrayifiedSelectedList: Array = []; + for (const [key, value] of Object.entries(checkedList)) { + if (value === true) { + arrayifiedSelectedList.push(key); + } + } + return arrayifiedSelectedList; +} + +export function selectedToKindSet(checkedList: TCheckedList): Set { + const setifiedList = new Set(); + for (const [key, value] of Object.entries(checkedList)) { + if (value === true) { + setifiedList.add(extractUuidKind(key) as string); + } + } + return setifiedList; +} + +function groupByKind(checkedList: TCheckedList, resources: ResourcesState): Record { + const result = {}; + selectedToArray(checkedList).forEach(uuid => { + const resource = getResource(uuid)(resources) as Resource; + if (!result[resource.kind]) result[resource.kind] = []; + result[resource.kind].push(resource); + }); + return result; +} + +function filterActions(actionArray: ContextMenuActionSet, filters: Set): Array { + return actionArray[0].filter(action => filters.has(action.name as string)); +} + +function selectActionsByKind(currentResourceKinds: Array, filterSet: TMultiselectActionsFilters) { + const rawResult: Set = new Set(); + const resultNames = new Set(); + const allFiltersArray: ContextMenuAction[][] = []; + currentResourceKinds.forEach(kind => { + if (filterSet[kind]) { + const actions = filterActions(...filterSet[kind]); + allFiltersArray.push(actions); + actions.forEach(action => { + if (!resultNames.has(action.name)) { + rawResult.add(action); + resultNames.add(action.name); + } + }); + } + }); + + const filteredNameSet = allFiltersArray.map(filterArray => { + const resultSet = new Set(); + filterArray.forEach(action => resultSet.add(action.name || "")); + return resultSet; + }); + + const filteredResult = Array.from(rawResult).filter(action => { + for (let i = 0; i < filteredNameSet.length; i++) { + if (!filteredNameSet[i].has(action.name)) return false; + } + return true; + }); + + return filteredResult.sort((a, b) => { + const nameA = a.name || ""; + const nameB = b.name || ""; + if (nameA < nameB) { + return -1; + } + if (nameA > nameB) { + return 1; + } + return 0; + }); +} + +//--------------------------------------------------// + function mapStateToProps(state: RootState) { + const { isVisible, checkedList } = state.multiselect; + return { + isVisible: isVisible, + checkedList: checkedList as TCheckedList, + resources: state.resources, + }; +} + +function mapDispatchToProps(dispatch: Dispatch) { return { - state: state, + executeMulti: (selectedAction: ContextMenuAction, checkedList: TCheckedList, resources: ResourcesState): void => { + const kindGroups = groupByKind(checkedList, resources); + switch (selectedAction.name) { + case contextMenuActionConsts.MOVE_TO: + const firstResource = getResource(selectedToArray(checkedList)[0])(resources) as Resource; + + const actionSet = kindToActionSet[firstResource.kind]; + const action = findActionByName(selectedAction.name as string, actionSet); + + if (action) action.execute(dispatch, kindGroups[firstResource.kind]); + break; + case contextMenuActionConsts.COPY_TO_CLIPBOARD: + const selectedResources = selectedToArray(checkedList).map(uuid => getResource(uuid)(resources)); + dispatch(copyToClipboardAction(selectedResources)); + break; + default: + for (const kind in kindGroups) { + const actionSet = kindToActionSet[kind]; + const action = findActionByName(selectedAction.name as string, actionSet); + + if (action) action.execute(dispatch, kindGroups[kind]); + } + break; + } + }, }; }