[ARVADOS-WORKBENCH2] created: 1.4.1-424-g22821296

Git user git at public.arvados.org
Fri Sep 11 18:51:41 UTC 2020


        at  22821296e913d4be63d4a40c33e7c28c5582cdd5 (commit)


commit 22821296e913d4be63d4a40c33e7c28c5582cdd5
Author: Daniel Kutyła <daniel.kutyla at contractors.roche.com>
Date:   Fri Sep 11 20:50:24 2020 +0200

    16243: Added filtering for collection files
    
    Arvados-DCO-1.1-Signed-off-by: Daniel Kutyła <daniel.kutyla at contractors.roche.com>

diff --git a/src/components/collection-panel-files/collection-panel-files.tsx b/src/components/collection-panel-files/collection-panel-files.tsx
index c7db48c4..f9c24b62 100644
--- a/src/components/collection-panel-files/collection-panel-files.tsx
+++ b/src/components/collection-panel-files/collection-panel-files.tsx
@@ -6,9 +6,11 @@ import * as React from 'react';
 import { TreeItem, TreeItemStatus } from '~/components/tree/tree';
 import { FileTreeData } from '~/components/file-tree/file-tree-data';
 import { FileTree } from '~/components/file-tree/file-tree';
+import { CollectionFileType } from "~/models/collection-file";
 import { IconButton, Grid, Typography, StyleRulesCallback, withStyles, WithStyles, CardHeader, Card, Button, Tooltip, CircularProgress } from '@material-ui/core';
 import { CustomizeTableIcon } from '~/components/icon/icon';
 import { DownloadIcon } from '~/components/icon/icon';
+import { SearchInput } from '../search-input/search-input';
 
 export interface CollectionPanelFilesProps {
     items: Array<TreeItem<FileTreeData>>;
@@ -16,6 +18,7 @@ export interface CollectionPanelFilesProps {
     isLoading: boolean;
     tooManyFiles: boolean;
     onUploadDataClick: () => void;
+    onSearchChange: (searchValue: string) => void;
     onItemMenuOpen: (event: React.MouseEvent<HTMLElement>, item: TreeItem<FileTreeData>, isWritable: boolean) => void;
     onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, isWritable: boolean) => void;
     onSelectionToggle: (event: React.MouseEvent<HTMLElement>, item: TreeItem<FileTreeData>) => void;
@@ -25,7 +28,7 @@ export interface CollectionPanelFilesProps {
     currentItemUuid?: string;
 }
 
-type CssRules = 'root' | 'cardSubheader' | 'nameHeader' | 'fileSizeHeader' | 'uploadIcon' | 'button' | 'centeredLabel';
+type CssRules = 'root' | 'cardSubheader' | 'nameHeader' | 'fileSizeHeader' | 'uploadIcon' | 'button' | 'centeredLabel' | 'cardHeaderContent' | 'cardHeaderContentTitle';
 
 const styles: StyleRulesCallback<CssRules> = theme => ({
     root: {
@@ -34,7 +37,18 @@ const styles: StyleRulesCallback<CssRules> = theme => ({
     },
     cardSubheader: {
         paddingTop: 0,
-        paddingBottom: 0
+        paddingBottom: 0,
+        minHeight: 8 * theme.spacing.unit,
+    },
+    cardHeaderContent: {
+        display: 'flex',
+        paddingRight: 2 * theme.spacing.unit,
+        justifyContent: 'space-between',
+    },
+    cardHeaderContentTitle: {
+        paddingLeft: theme.spacing.unit,
+        paddingTop: 2 * theme.spacing.unit,
+        paddingRight: 2 * theme.spacing.unit,
     },
     nameHeader: {
         marginLeft: '75px'
@@ -47,7 +61,7 @@ const styles: StyleRulesCallback<CssRules> = theme => ({
     },
     button: {
         marginRight: -theme.spacing.unit,
-        marginTop: '0px'
+        marginTop: '8px'
     },
     centeredLabel: {
         fontSize: '0.875rem',
@@ -55,52 +69,80 @@ const styles: StyleRulesCallback<CssRules> = theme => ({
     },
 });
 
+
+
 export const CollectionPanelFiles =
     withStyles(styles)(
-        ({ onItemMenuOpen, onOptionsMenuOpen, onUploadDataClick, classes,
-            isWritable, isLoading, tooManyFiles, loadFilesFunc, ...treeProps }: CollectionPanelFilesProps & WithStyles<CssRules>) =>
-            <Card data-cy='collection-files-panel' className={classes.root}>
+        ({ onItemMenuOpen, onSearchChange, onOptionsMenuOpen, onUploadDataClick, classes,
+            isWritable, isLoading, tooManyFiles, loadFilesFunc, ...treeProps }: CollectionPanelFilesProps & WithStyles<CssRules>) => {
+            const { useState, useEffect } = React;
+            const [searchValue, setSearchValue] = useState('');
+
+            useEffect(() => {
+                onSearchChange(searchValue);
+            }, [searchValue]);
+
+            return (<Card data-cy='collection-files-panel' className={classes.root}>
                 <CardHeader
-                    title="Files"
+                    title={
+                        <div className={classes.cardHeaderContent}>
+                            <span className={classes.cardHeaderContentTitle}>Files</span>
+                            <SearchInput
+                                value={searchValue}
+                                onSearch={setSearchValue} />
+                        </div>
+                    }
                     className={classes.cardSubheader}
                     classes={{ action: classes.button }}
                     action={<>
                         {isWritable &&
-                        <Button
-                            data-cy='upload-button'
-                            onClick={onUploadDataClick}
-                            variant='contained'
-                            color='primary'
-                            size='small'>
-                            <DownloadIcon className={classes.uploadIcon} />
+                            <Button
+                                data-cy='upload-button'
+                                onClick={onUploadDataClick}
+                                variant='contained'
+                                color='primary'
+                                size='small'>
+                                <DownloadIcon className={classes.uploadIcon} />
                             Upload data
                         </Button>}
                         {!tooManyFiles &&
-                        <Tooltip title="More options" disableFocusListener>
-                            <IconButton
-                                data-cy='collection-files-panel-options-btn'
-                                onClick={(ev) => onOptionsMenuOpen(ev, isWritable)}>
-                                <CustomizeTableIcon />
-                            </IconButton>
-                        </Tooltip>}
+                            <Tooltip title="More options" disableFocusListener>
+                                <IconButton
+                                    data-cy='collection-files-panel-options-btn'
+                                    onClick={(ev) => onOptionsMenuOpen(ev, isWritable)}>
+                                    <CustomizeTableIcon />
+                                </IconButton>
+                            </Tooltip>}
                     </>
-                } />
-                { tooManyFiles
-                ? <div className={classes.centeredLabel}>
-                        File listing may take some time, please click to browse: <Button onClick={loadFilesFunc}><DownloadIcon/>Show files</Button>
-                </div>
-                : <>
-                    <Grid container justify="space-between">
-                        <Typography variant="caption" className={classes.nameHeader}>
-                            Name
+                    } />
+                {tooManyFiles
+                    ? <div className={classes.centeredLabel}>
+                        File listing may take some time, please click to browse: <Button onClick={loadFilesFunc}><DownloadIcon />Show files</Button>
+                    </div>
+                    : <>
+                        <Grid container justify="space-between">
+                            <Typography variant="caption" className={classes.nameHeader}>
+                                Name
                         </Typography>
-                        <Typography variant="caption" className={classes.fileSizeHeader}>
-                            File size
+                            <Typography variant="caption" className={classes.fileSizeHeader}>
+                                File size
                         </Typography>
-                    </Grid>
-                    { isLoading
-                    ? <div className={classes.centeredLabel}><CircularProgress /></div>
-                    : <div style={{height: 'calc(100% - 60px)'}}><FileTree onMenuOpen={(ev, item) => onItemMenuOpen(ev, item, isWritable)} {...treeProps} /></div> }
-                </>
+                        </Grid>
+                        {isLoading
+                            ? <div className={classes.centeredLabel}><CircularProgress /></div>
+                            : <div style={{ height: 'calc(100% - 60px)' }}>
+                                <FileTree
+                                    onMenuOpen={(ev, item) => onItemMenuOpen(ev, item, isWritable)}
+                                    {...treeProps}
+                                    items={treeProps.items.filter((item) => {
+                                        if (item.data.type === CollectionFileType.FILE) {
+                                            return item.data.name.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
+                                        }
+
+                                        return true;
+                                    })} /></div>}
+                    </>
                 }
             </Card>);
+        }
+    );
diff --git a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
index 204d4c0e..704e2999 100644
--- a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
+++ b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
@@ -22,6 +22,7 @@ export const collectionPanelFilesAction = unionize({
     TOGGLE_COLLECTION_FILE_SELECTION: ofType<{ id: string }>(),
     SELECT_ALL_COLLECTION_FILES: ofType<{}>(),
     UNSELECT_ALL_COLLECTION_FILES: ofType<{}>(),
+    ON_SEARCH_CHANGE: ofType<string>(),
 });
 
 export type CollectionPanelFilesAction = UnionOf<typeof collectionPanelFilesAction>;
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 08a71759..01f41f0e 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
@@ -12,21 +12,30 @@ export const collectionPanelFilesReducer = (state: CollectionPanelFilesState = c
     // 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)),
+            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: (data) =>
+            mapTreeValues((v: CollectionPanelDirectory | CollectionPanelFile) => {
+                if (v.type === CollectionFileType.DIRECTORY) {
+                    return ({ ...v, collapsed: data.length === 0 });
+                }
+
+                return ({ ...v });
+            })({ ...state }),
+
         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;
diff --git a/src/views-components/collection-panel-files/collection-panel-files.ts b/src/views-components/collection-panel-files/collection-panel-files.ts
index 79970003..9859f84b 100644
--- a/src/views-components/collection-panel-files/collection-panel-files.ts
+++ b/src/views-components/collection-panel-files/collection-panel-files.ts
@@ -44,7 +44,7 @@ const memoizedMapStateToProps = () => {
     };
 };
 
-const mapDispatchToProps = (dispatch: Dispatch): Pick<CollectionPanelFilesProps, 'onFileClick' | 'onUploadDataClick' | 'onCollapseToggle' | 'onSelectionToggle' | 'onItemMenuOpen' | 'onOptionsMenuOpen'> => ({
+const mapDispatchToProps = (dispatch: Dispatch): Pick<CollectionPanelFilesProps, 'onSearchChange' | 'onFileClick' | 'onUploadDataClick' | 'onCollapseToggle' | 'onSelectionToggle' | 'onItemMenuOpen' | 'onOptionsMenuOpen'> => ({
     onUploadDataClick: () => {
         dispatch<any>(openUploadCollectionFilesDialog());
     },
@@ -68,6 +68,9 @@ const mapDispatchToProps = (dispatch: Dispatch): Pick<CollectionPanelFilesProps,
             }
         ));
     },
+    onSearchChange: (searchValue: string) => {
+        dispatch(collectionPanelFilesAction.ON_SEARCH_CHANGE(searchValue));
+    },
     onOptionsMenuOpen: (event, isWritable) => {
         dispatch<any>(openCollectionFilesContextMenu(event, isWritable));
     },

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list