16243: Added filtering for collection files
[arvados-workbench2.git] / src / components / collection-panel-files / collection-panel-files.tsx
index c7db48c4b8b5bc63952491a19076cb27bacece49..f9c24b627b64a8eda60af2449232350e995e24e2 100644 (file)
@@ -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>);
+        }
+    );