X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/e13e7dd672160e4ab5569c24133f4f6032db4a9a..ffbfe1965a34800f933b20a32374d9cd9eb7ea72:/src/store/collection-panel/collection-panel-files/collection-panel-files-reducer.ts diff --git a/src/store/collection-panel/collection-panel-files/collection-panel-files-reducer.ts b/src/store/collection-panel/collection-panel-files/collection-panel-files-reducer.ts index 08b60308..03de8e34 100644 --- a/src/store/collection-panel/collection-panel-files/collection-panel-files-reducer.ts +++ b/src/store/collection-panel/collection-panel-files/collection-panel-files-reducer.ts @@ -2,29 +2,91 @@ // // SPDX-License-Identifier: AGPL-3.0 -import { CollectionPanelFilesState, CollectionPanelFile, CollectionPanelDirectory, mapCollectionFileToCollectionPanelFile, mergeCollectionPanelFilesStates } from "./collection-panel-files-state"; +import { CollectionPanelFilesState, CollectionPanelFile, CollectionPanelDirectory, mapCollectionFileToCollectionPanelFile, mergeCollectionPanelFilesStates } from './collection-panel-files-state'; import { CollectionPanelFilesAction, collectionPanelFilesAction } from "./collection-panel-files-actions"; -import { createTree, mapTreeValues, getNode, setNode, getNodeAncestors, getNodeDescendants, setNodeValueWith, mapTree } from "~/models/tree"; +import { createTree, mapTreeValues, getNode, setNode, getNodeAncestorsIds, getNodeDescendantsIds, setNodeValueWith, mapTree } from "~/models/tree"; import { CollectionFileType } from "~/models/collection-file"; +let fetchedFiles: any = {}; + export const collectionPanelFilesReducer = (state: CollectionPanelFilesState = createTree(), action: CollectionPanelFilesAction) => { + // Low-level tree handling setNode() func does in-place data modifications + // for performance reasons, so we pass a copy of 'state' to avoid side effects. return collectionPanelFilesAction.match(action, { - SET_COLLECTION_FILES: files => - mergeCollectionPanelFilesStates(state, mapTree(mapCollectionFileToCollectionPanelFile)(files)), + SET_COLLECTION_FILES: files => { + fetchedFiles = files; + return mergeCollectionPanelFilesStates({ ...state }, mapTree(mapCollectionFileToCollectionPanelFile)(files)); + }, TOGGLE_COLLECTION_FILE_COLLAPSE: data => - toggleCollapse(data.id)(state), + toggleCollapse(data.id)({ ...state }), - TOGGLE_COLLECTION_FILE_SELECTION: data => [state] + TOGGLE_COLLECTION_FILE_SELECTION: data => [{ ...state }] .map(toggleSelected(data.id)) .map(toggleAncestors(data.id)) .map(toggleDescendants(data.id))[0], + ON_SEARCH_CHANGE: (searchValue) => { + const fileIds: string[] = []; + const directoryIds: string[] = []; + const filteredFiles = Object.keys(fetchedFiles) + .filter((key: string) => { + const node = fetchedFiles[key]; + + if (node.value === undefined) { + return false; + } + + const { id, value: { type, name } } = node; + + if (type === CollectionFileType.DIRECTORY) { + directoryIds.push(id); + return true; + } + + const includeFile = name.toLowerCase().indexOf(searchValue.toLowerCase()) > -1; + + if (includeFile) { + fileIds.push(id); + } + + return includeFile; + }) + .reduce((prev, next) => { + const node = JSON.parse(JSON.stringify(fetchedFiles[next])); + const { value: { type }, children } = node; + + node.children = node.children.filter((key: string) => { + const isFile = directoryIds.indexOf(key) === -1; + return isFile ? + fileIds.indexOf(key) > -1 : + !!fileIds.find(id => id.indexOf(key) > -1); + }); + + if (type === CollectionFileType.FILE || children.length > 0) { + prev[next] = node; + } + + return prev; + }, {}); + + return mapTreeValues((v: CollectionPanelDirectory | CollectionPanelFile) => { + if (v.type === CollectionFileType.DIRECTORY) { + return ({ + ...v, + collapsed: searchValue.length === 0, + }); + } + + return ({ ...v }); + })({ ...filteredFiles }); + }, + SELECT_ALL_COLLECTION_FILES: () => - mapTreeValues(v => ({ ...v, selected: true }))(state), + mapTreeValues(v => ({ ...v, selected: true }))({ ...state }), UNSELECT_ALL_COLLECTION_FILES: () => - mapTreeValues(v => ({ ...v, selected: false }))(state), + mapTreeValues(v => ({ ...v, selected: false }))({ ...state }), default: () => state }) as CollectionPanelFilesState; @@ -44,7 +106,7 @@ const toggleSelected = (id: string) => (tree: CollectionPanelFilesState) => const toggleDescendants = (id: string) => (tree: CollectionPanelFilesState) => { const node = getNode(id)(tree); if (node && node.value.type === CollectionFileType.DIRECTORY) { - return getNodeDescendants(id)(tree) + return getNodeDescendantsIds(id)(tree) .reduce((newTree, id) => setNodeValueWith(v => ({ ...v, selected: node.value.selected }))(id)(newTree), tree); } @@ -52,7 +114,7 @@ const toggleDescendants = (id: string) => (tree: CollectionPanelFilesState) => { }; const toggleAncestors = (id: string) => (tree: CollectionPanelFilesState) => { - const ancestors = getNodeAncestors(id)(tree).reverse(); + const ancestors = getNodeAncestorsIds(id)(tree).reverse(); return ancestors.reduce((newTree, parent) => parent ? toggleParentNode(parent)(newTree) : newTree, tree); };