15768: non-functional checkboxes in place Arvados-DCO-1.1-Signed-off-by: Lisa Knox...
authorLisa Knox <lisaknox83@gmail.com>
Tue, 18 Apr 2023 21:56:01 +0000 (17:56 -0400)
committerLisa Knox <lisaknox83@gmail.com>
Tue, 18 Apr 2023 21:58:25 +0000 (17:58 -0400)
src/components/data-explorer/data-explorer.tsx
src/components/data-table/data-table.tsx
src/views-components/data-explorer/renderers.tsx
src/views/project-panel/project-panel.tsx

index fcee0c54deedcefaf5f9ed3282bfa757ccaadd4b..ea95648e7b8b48bfd7866461e22f8fc9d67fbe00 100644 (file)
@@ -4,24 +4,18 @@
 
 import React from 'react';
 import { Grid, Paper, Toolbar, StyleRulesCallback, withStyles, WithStyles, TablePagination, IconButton, Tooltip, Button } from '@material-ui/core';
-import { ColumnSelector } from "components/column-selector/column-selector";
-import { DataTable, DataColumns, DataTableFetchMode } from "components/data-table/data-table";
-import { DataColumn } from "components/data-table/data-column";
+import { ColumnSelector } from 'components/column-selector/column-selector';
+import { DataTable, DataColumns, DataTableFetchMode } from 'components/data-table/data-table';
+import { DataColumn } from 'components/data-table/data-column';
 import { SearchInput } from 'components/search-input/search-input';
-import { ArvadosTheme } from "common/custom-theme";
+import { ArvadosTheme } from 'common/custom-theme';
 import { createTree } from 'models/tree';
 import { DataTableFilters } from 'components/data-table-filters/data-table-filters-tree';
-import {
-    CloseIcon,
-    IconType,
-    MaximizeIcon,
-    UnMaximizeIcon,
-    MoreOptionsIcon
-} from 'components/icon/icon';
+import { CloseIcon, IconType, MaximizeIcon, UnMaximizeIcon, MoreOptionsIcon } from 'components/icon/icon';
 import { PaperProps } from '@material-ui/core/Paper';
 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
 
-type CssRules = 'searchBox' | 'headerMenu' | "toolbar" | "footer" | "root" | 'moreOptionsButton' | 'title' | 'dataTable' | 'container';
+type CssRules = 'searchBox' | 'headerMenu' | 'toolbar' | 'footer' | 'root' | 'moreOptionsButton' | 'title' | 'dataTable' | 'container';
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     searchBox: {
@@ -32,19 +26,19 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         paddingRight: theme.spacing.unit,
     },
     footer: {
-        overflow: 'auto'
+        overflow: 'auto',
     },
     root: {
         height: '100%',
     },
     moreOptionsButton: {
-        padding: 0
+        padding: 0,
     },
     title: {
         display: 'inline-block',
         paddingLeft: theme.spacing.unit * 2,
         paddingTop: theme.spacing.unit * 2,
-        fontSize: '18px'
+        fontSize: '18px',
     },
     dataTable: {
         height: '100%',
@@ -56,7 +50,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     headerMenu: {
         float: 'right',
         display: 'inline-block',
-    }
+    },
 });
 
 interface DataExplorerDataProps<T> {
@@ -100,8 +94,7 @@ interface DataExplorerActionProps<T> {
     extractKey?: (item: T) => React.Key;
 }
 
-type DataExplorerProps<T> = DataExplorerDataProps<T> &
-    DataExplorerActionProps<T> & WithStyles<CssRules> & MPVPanelProps;
+type DataExplorerProps<T> = DataExplorerDataProps<T> & DataExplorerActionProps<T> & WithStyles<CssRules> & MPVPanelProps;
 
 export const DataExplorer = withStyles(styles)(
     class DataExplorerGeneric<T> extends React.Component<DataExplorerProps<T>> {
@@ -153,120 +146,162 @@ export const DataExplorer = withStyles(styles)(
 
         render() {
             const {
-                columns, onContextMenu, onFiltersChange, onSortToggle, extractKey,
-                rowsPerPage, rowsPerPageOptions, onColumnToggle, searchLabel, searchValue, onSearch,
-                items, itemsAvailable, onRowClick, onRowDoubleClick, classes,
-                defaultViewIcon, defaultViewMessages, hideColumnSelector, actions, paperProps, hideSearchInput,
-                paperKey, fetchMode, currentItemUuid, title,
-                doHidePanel, doMaximizePanel, doUnMaximizePanel, panelName, panelMaximized, elementPath
+                columns,
+                onContextMenu,
+                onFiltersChange,
+                onSortToggle,
+                extractKey,
+                rowsPerPage,
+                rowsPerPageOptions,
+                onColumnToggle,
+                searchLabel,
+                searchValue,
+                onSearch,
+                items,
+                itemsAvailable,
+                onRowClick,
+                onRowDoubleClick,
+                classes,
+                defaultViewIcon,
+                defaultViewMessages,
+                hideColumnSelector,
+                actions,
+                paperProps,
+                hideSearchInput,
+                paperKey,
+                fetchMode,
+                currentItemUuid,
+                title,
+                doHidePanel,
+                doMaximizePanel,
+                doUnMaximizePanel,
+                panelName,
+                panelMaximized,
+                elementPath,
             } = this.props;
-            return <Paper className={classes.root} {...paperProps} key={paperKey} data-cy={this.props["data-cy"]}>
-                <Grid container direction="column" wrap="nowrap" className={classes.container}>
-                    <div>
-                        {title && <Grid item xs className={classes.title}>{title}</Grid>}
-                        {
-                            (!hideColumnSelector || !hideSearchInput || !!actions) &&
-                            <Grid className={classes.headerMenu} item xs>
-                                <Toolbar className={classes.toolbar}>
-                                    {!hideSearchInput && <div className={classes.searchBox}>
-                                        {!hideSearchInput && <SearchInput
-                                            label={searchLabel}
-                                            value={searchValue}
-                                            selfClearProp={''}
-                                            onSearch={onSearch} />}
-                                    </div>}
-                                    {actions}
-                                    {!hideColumnSelector && <ColumnSelector
-                                        columns={columns}
-                                        onColumnToggle={onColumnToggle} />}
-                                    { doUnMaximizePanel && panelMaximized &&
-                                    <Tooltip title={`Unmaximize ${panelName || 'panel'}`} disableFocusListener>
-                                        <IconButton onClick={doUnMaximizePanel}><UnMaximizeIcon /></IconButton>
-                                    </Tooltip> }
-                                    { doMaximizePanel && !panelMaximized &&
-                                        <Tooltip title={`Maximize ${panelName || 'panel'}`} disableFocusListener>
-                                            <IconButton onClick={doMaximizePanel}><MaximizeIcon /></IconButton>
-                                        </Tooltip> }
-                                    { doHidePanel &&
-                                        <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
-                                            <IconButton disabled={panelMaximized} onClick={doHidePanel}><CloseIcon /></IconButton>
-                                        </Tooltip> }
-                                </Toolbar>
-                            </Grid>
-                        }
-                    </div>
-                <Grid item xs="auto" className={classes.dataTable}><DataTable
-                    columns={this.props.contextMenuColumn ? [...columns, this.contextMenuColumn] : columns}
-                    items={items}
-                    onRowClick={(_, item: T) => onRowClick(item)}
-                    onContextMenu={onContextMenu}
-                    onRowDoubleClick={(_, item: T) => onRowDoubleClick(item)}
-                    onFiltersChange={onFiltersChange}
-                    onSortToggle={onSortToggle}
-                    extractKey={extractKey}
-                    working={this.state.showLoading}
-                    defaultViewIcon={defaultViewIcon}
-                    defaultViewMessages={defaultViewMessages}
-                    currentItemUuid={currentItemUuid}
-                    currentRoute={paperKey} /></Grid>
-                <Grid item xs><Toolbar className={classes.footer}>
-                    {
-                        elementPath &&
-                        <Grid container>
-                            <span data-cy="element-path">
-                                {elementPath}
-                            </span>
+            return (
+                <Paper className={classes.root} {...paperProps} key={paperKey} data-cy={this.props['data-cy']}>
+                    <Grid container direction='column' wrap='nowrap' className={classes.container}>
+                        <div>
+                            {title && (
+                                <Grid item xs className={classes.title}>
+                                    {title}
+                                </Grid>
+                            )}
+                            {(!hideColumnSelector || !hideSearchInput || !!actions) && (
+                                <Grid className={classes.headerMenu} item xs>
+                                    <Toolbar className={classes.toolbar}>
+                                        {!hideSearchInput && (
+                                            <div className={classes.searchBox}>
+                                                {!hideSearchInput && <SearchInput label={searchLabel} value={searchValue} selfClearProp={''} onSearch={onSearch} />}
+                                            </div>
+                                        )}
+                                        {actions}
+                                        {!hideColumnSelector && <ColumnSelector columns={columns} onColumnToggle={onColumnToggle} />}
+                                        {doUnMaximizePanel && panelMaximized && (
+                                            <Tooltip title={`Unmaximize ${panelName || 'panel'}`} disableFocusListener>
+                                                <IconButton onClick={doUnMaximizePanel}>
+                                                    <UnMaximizeIcon />
+                                                </IconButton>
+                                            </Tooltip>
+                                        )}
+                                        {doMaximizePanel && !panelMaximized && (
+                                            <Tooltip title={`Maximize ${panelName || 'panel'}`} disableFocusListener>
+                                                <IconButton onClick={doMaximizePanel}>
+                                                    <MaximizeIcon />
+                                                </IconButton>
+                                            </Tooltip>
+                                        )}
+                                        {doHidePanel && (
+                                            <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
+                                                <IconButton disabled={panelMaximized} onClick={doHidePanel}>
+                                                    <CloseIcon />
+                                                </IconButton>
+                                            </Tooltip>
+                                        )}
+                                    </Toolbar>
+                                </Grid>
+                            )}
+                        </div>
+                        <Grid item xs='auto' className={classes.dataTable}>
+                            <DataTable
+                                columns={this.props.contextMenuColumn ? [...columns, this.contextMenuColumn] : columns}
+                                items={items}
+                                onRowClick={(_, item: T) => onRowClick(item)}
+                                onContextMenu={onContextMenu}
+                                onRowDoubleClick={(_, item: T) => onRowDoubleClick(item)}
+                                onFiltersChange={onFiltersChange}
+                                onSortToggle={onSortToggle}
+                                extractKey={extractKey}
+                                working={this.state.showLoading}
+                                defaultViewIcon={defaultViewIcon}
+                                defaultViewMessages={defaultViewMessages}
+                                currentItemUuid={currentItemUuid}
+                                currentRoute={paperKey}
+                            />
+                        </Grid>
+                        <Grid item xs>
+                            <Toolbar className={classes.footer}>
+                                {elementPath && (
+                                    <Grid container>
+                                        <span data-cy='element-path'>{elementPath}</span>
+                                    </Grid>
+                                )}
+                                <Grid container={!elementPath} justify='flex-end'>
+                                    {fetchMode === DataTableFetchMode.PAGINATED ? (
+                                        <TablePagination
+                                            count={itemsAvailable}
+                                            rowsPerPage={rowsPerPage}
+                                            rowsPerPageOptions={rowsPerPageOptions}
+                                            page={this.props.page}
+                                            onChangePage={this.changePage}
+                                            onChangeRowsPerPage={this.changeRowsPerPage}
+                                            // Disable next button on empty lists since that's not default behavior
+                                            nextIconButtonProps={itemsAvailable > 0 ? {} : { disabled: true }}
+                                            component='div'
+                                        />
+                                    ) : (
+                                        <Button variant='text' size='medium' onClick={this.loadMore}>
+                                            Load more
+                                        </Button>
+                                    )}
+                                </Grid>
+                            </Toolbar>
                         </Grid>
-                    }
-                    <Grid container={!elementPath} justify="flex-end">
-                        {fetchMode === DataTableFetchMode.PAGINATED ? <TablePagination
-                            count={itemsAvailable}
-                            rowsPerPage={rowsPerPage}
-                            rowsPerPageOptions={rowsPerPageOptions}
-                            page={this.props.page}
-                            onChangePage={this.changePage}
-                            onChangeRowsPerPage={this.changeRowsPerPage}
-                            // Disable next button on empty lists since that's not default behavior
-                            nextIconButtonProps={(itemsAvailable > 0) ? {} : {disabled: true}}
-                            component="div" /> : <Button
-                                variant="text"
-                                size="medium"
-                                onClick={this.loadMore}
-                            >Load more</Button>}
                     </Grid>
-                </Toolbar></Grid>
-                </Grid>
-            </Paper>;
+                </Paper>
+            );
         }
 
         changePage = (event: React.MouseEvent<HTMLButtonElement>, page: number) => {
             this.props.onChangePage(page);
-        }
+        };
 
         changeRowsPerPage: React.ChangeEventHandler<HTMLTextAreaElement | HTMLInputElement> = (event) => {
             this.props.onChangeRowsPerPage(parseInt(event.target.value, 10));
-        }
+        };
 
         loadMore = () => {
             this.props.onLoadMore(this.props.page + 1);
-        }
+        };
 
-        renderContextMenuTrigger = (item: T) =>
-            <Grid container justify="center">
-                <Tooltip title="More options" disableFocusListener>
-                    <IconButton className={this.props.classes.moreOptionsButton} onClick={event => this.props.onContextMenu(event, item)}>
+        renderContextMenuTrigger = (item: T) => (
+            <Grid container justify='center'>
+                <Tooltip title='More options' disableFocusListener>
+                    <IconButton className={this.props.classes.moreOptionsButton} onClick={(event) => this.props.onContextMenu(event, item)}>
                         <MoreOptionsIcon />
                     </IconButton>
                 </Tooltip>
             </Grid>
+        );
 
         contextMenuColumn: DataColumn<any, any> = {
-            name: "Actions",
+            name: 'Actions',
             selected: true,
             configurable: false,
             filters: createTree(),
-            key: "context-actions",
-            render: this.renderContextMenuTrigger
+            key: 'context-actions',
+            render: this.renderContextMenuTrigger,
         };
     }
 );
index 4a82b6607c32ed44ecb77ea54bdd8a6cc1ab4a10..0d53f33159ce80168c18e8dadb3e332825894f88 100644 (file)
@@ -18,7 +18,7 @@ export type DataColumns<I, R> = Array<DataColumn<I, R>>;
 
 export enum DataTableFetchMode {
     PAGINATED,
-    INFINITE
+    INFINITE,
 }
 
 export interface DataTableDataProps<I> {
@@ -37,7 +37,7 @@ export interface DataTableDataProps<I> {
     currentRoute?: string;
 }
 
-type CssRules = "tableBody" | "root" | "content" | "noItemsInfo" | 'tableCell' | 'arrow' | 'arrowButton' | 'tableCellWorkflows' | 'loader';
+type CssRules = 'tableBody' | 'root' | 'content' | 'noItemsInfo' | 'tableCellSelect' | 'tableCell' | 'arrow' | 'arrowButton' | 'tableCellWorkflows' | 'loader';
 
 const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
     root: {
@@ -48,40 +48,42 @@ const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
         width: '100%',
     },
     tableBody: {
-        background: theme.palette.background.paper
+        background: theme.palette.background.paper,
     },
     loader: {
         left: '50%',
         marginLeft: '-84px',
-        position: 'absolute'
+        position: 'absolute',
     },
     noItemsInfo: {
-        textAlign: "center",
-        padding: theme.spacing.unit
+        textAlign: 'center',
+        padding: theme.spacing.unit,
+    },
+    tableCellSelect: {
+        padding: '0',
     },
     tableCell: {
         wordWrap: 'break-word',
         paddingRight: '24px',
-        color: '#737373'
-
+        color: '#737373',
     },
     tableCellWorkflows: {
         '&:nth-last-child(2)': {
             padding: '0px',
-            maxWidth: '48px'
+            maxWidth: '48px',
         },
         '&:last-child': {
             padding: '0px',
             paddingRight: '24px',
-            width: '48px'
-        }
+            width: '48px',
+        },
     },
     arrow: {
-        margin: 0
+        margin: 0,
     },
     arrowButton: {
-        color: theme.palette.text.primary
-    }
+        color: theme.palette.text.primary,
+    },
 });
 
 type DataTableProps<T> = DataTableDataProps<T> & WithStyles<CssRules>;
@@ -90,99 +92,97 @@ export const DataTable = withStyles(styles)(
     class Component<T> extends React.Component<DataTableProps<T>> {
         render() {
             const { items, classes, working } = this.props;
-            return <div className={classes.root}>
-                <div className={classes.content}>
-                    <Table>
-                        <TableHead>
-                            <TableRow>
-                                {this.mapVisibleColumns(this.renderHeadCell)}
-                            </TableRow>
-                        </TableHead>
-                        <TableBody className={classes.tableBody}>
-                            { !working && items.map(this.renderBodyRow) }
-                        </TableBody>
-                    </Table>
-                    { !!working &&
-                        <div className={classes.loader}>
-                            <DataTableDefaultView
-                                icon={PendingIcon}
-                                messages={['Loading data, please wait.']} />
-                        </div> }
-                    {items.length === 0 && !working && this.renderNoItemsPlaceholder(this.props.columns)}
+            return (
+                <div className={classes.root}>
+                    <div className={classes.content}>
+                        <Table>
+                            <TableHead>
+                                <TableRow>{this.mapVisibleColumns(this.renderHeadCell)}</TableRow>
+                            </TableHead>
+                            <TableBody className={classes.tableBody}>{!working && items.map(this.renderBodyRow)}</TableBody>
+                        </Table>
+                        {!!working && (
+                            <div className={classes.loader}>
+                                <DataTableDefaultView icon={PendingIcon} messages={['Loading data, please wait.']} />
+                            </div>
+                        )}
+                        {items.length === 0 && !working && this.renderNoItemsPlaceholder(this.props.columns)}
+                    </div>
                 </div>
-            </div>;
+            );
         }
 
         renderNoItemsPlaceholder = (columns: DataColumns<T, any>) => {
             const dirty = columns.some((column) => getTreeDirty('')(column.filters));
-            return <DataTableDefaultView
-                icon={this.props.defaultViewIcon}
-                messages={this.props.defaultViewMessages}
-                filtersApplied={dirty} />;
-        }
+            return <DataTableDefaultView icon={this.props.defaultViewIcon} messages={this.props.defaultViewMessages} filtersApplied={dirty} />;
+        };
 
         renderHeadCell = (column: DataColumn<T, any>, index: number) => {
             const { name, key, renderHeader, filters, sort } = column;
             const { onSortToggle, onFiltersChange, classes } = this.props;
-            return <TableCell className={classes.tableCell} key={key || index}>
-                {renderHeader ?
-                    renderHeader() :
-                    countNodes(filters) > 0
-                        ? <DataTableFiltersPopover
+            return (
+                <TableCell className={classes.tableCell} key={key || index}>
+                    {renderHeader ? (
+                        renderHeader()
+                    ) : countNodes(filters) > 0 ? (
+                        <DataTableFiltersPopover
                             name={`${name} filters`}
                             mutuallyExclusive={column.mutuallyExclusiveFilters}
-                            onChange={filters =>
-                                onFiltersChange &&
-                                onFiltersChange(filters, column)}
-                            filters={filters}>
+                            onChange={(filters) => onFiltersChange && onFiltersChange(filters, column)}
+                            filters={filters}
+                        >
                             {name}
                         </DataTableFiltersPopover>
-                        : sort
-                            ? <TableSortLabel
-                                active={sort.direction !== SortDirection.NONE}
-                                direction={sort.direction !== SortDirection.NONE ? sort.direction : undefined}
-                                IconComponent={this.ArrowIcon}
-                                hideSortIcon
-                                onClick={() =>
-                                    onSortToggle &&
-                                    onSortToggle(column)}>
-                                {name}
-                            </TableSortLabel>
-                            : <span>
-                                {name}
-                            </span>}
-            </TableCell>;
-        }
+                    ) : sort ? (
+                        <TableSortLabel
+                            active={sort.direction !== SortDirection.NONE}
+                            direction={sort.direction !== SortDirection.NONE ? sort.direction : undefined}
+                            IconComponent={this.ArrowIcon}
+                            hideSortIcon
+                            onClick={() => onSortToggle && onSortToggle(column)}
+                        >
+                            {name}
+                        </TableSortLabel>
+                    ) : (
+                        <span>{name}</span>
+                    )}
+                </TableCell>
+            );
+        };
 
         ArrowIcon = ({ className, ...props }: SvgIconProps) => (
             <IconButton component='span' className={this.props.classes.arrowButton} tabIndex={-1}>
                 <ArrowDownwardIcon {...props} className={classnames(className, this.props.classes.arrow)} />
             </IconButton>
-        )
+        );
 
         renderBodyRow = (item: any, index: number) => {
             const { onRowClick, onRowDoubleClick, extractKey, classes, currentItemUuid, currentRoute } = this.props;
-            return <TableRow
-                hover
-                key={extractKey ? extractKey(item) : index}
-                onClick={event => onRowClick && onRowClick(event, item)}
-                onContextMenu={this.handleRowContextMenu(item)}
-                onDoubleClick={event => onRowDoubleClick && onRowDoubleClick(event, item)}
-                selected={item === currentItemUuid}>
-                {this.mapVisibleColumns((column, index) => <TableCell key={column.key || index} className={currentRoute === '/workflows' ? classes.tableCellWorkflows : classes.tableCell}>
-                        {column.render(item)}
-                    </TableCell>
-                )}
-            </TableRow>;
-        }
+            return (
+                <TableRow
+                    hover
+                    key={extractKey ? extractKey(item) : index}
+                    onClick={(event) => onRowClick && onRowClick(event, item)}
+                    onContextMenu={this.handleRowContextMenu(item)}
+                    onDoubleClick={(event) => onRowDoubleClick && onRowDoubleClick(event, item)}
+                    selected={item === currentItemUuid}
+                >
+                    {this.mapVisibleColumns((column, index) => (
+                        <TableCell
+                            key={column.key || index}
+                            className={currentRoute === '/workflows' ? classes.tableCellWorkflows : index === 0 ? classes.tableCellSelect : classes.tableCell}
+                        >
+                            {column.render(item)}
+                        </TableCell>
+                    ))}
+                </TableRow>
+            );
+        };
 
         mapVisibleColumns = (fn: (column: DataColumn<T, any>, index: number) => React.ReactElement<any>) => {
-            return this.props.columns.filter(column => column.selected).map(fn);
-        }
-
-        handleRowContextMenu = (item: T) =>
-            (event: React.MouseEvent<HTMLElement>) =>
-                this.props.onContextMenu(event, item)
+            return this.props.columns.filter((column) => column.selected).map(fn);
+        };
 
+        handleRowContextMenu = (item: T) => (event: React.MouseEvent<HTMLElement>) => this.props.onContextMenu(event, item);
     }
 );
index d274157c48e2b1cd22804179fa33954c4b8fb361..c8e14208e5e5fffa1d54c7da3b44eadfd112fdb2 100644 (file)
@@ -3,15 +3,7 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import React from 'react';
-import {
-    Grid,
-    Typography,
-    withStyles,
-    Tooltip,
-    IconButton,
-    Checkbox,
-    Chip
-} from '@material-ui/core';
+import { Grid, Typography, withStyles, Tooltip, IconButton, Checkbox, Chip } from '@material-ui/core';
 import { FavoriteStar, PublicFavoriteStar } from '../favorite-star/favorite-star';
 import { Resource, ResourceKind, TrashableResource } from 'models/resource';
 import {
@@ -63,59 +55,60 @@ import { CopyToClipboardSnackbar } from 'components/copy-to-clipboard-snackbar/c
 import { ProjectResource } from 'models/project';
 import { ProcessResource } from 'models/process';
 
-
 const renderName = (dispatch: Dispatch, item: GroupContentsResource) => {
-    const navFunc = ("groupClass" in item && item.groupClass === GroupClass.ROLE ? navigateToGroupDetails : navigateTo);
-    return <Grid container alignItems="center" wrap="nowrap" spacing={16}>
-        <Grid item>
-            {renderIcon(item)}
-        </Grid>
-        <Grid item>
-            <Typography color="primary" style={{ width: 'auto', cursor: 'pointer' }} onClick={() => dispatch<any>(navFunc(item.uuid))}>
-                {item.kind === ResourceKind.PROJECT || item.kind === ResourceKind.COLLECTION
-                    ? <IllegalNamingWarning name={item.name} />
-                    : null}
-                {item.name}
-            </Typography>
-        </Grid>
-        <Grid item>
-            <Typography variant="caption">
-                <FavoriteStar resourceUuid={item.uuid} />
-                <PublicFavoriteStar resourceUuid={item.uuid} />
-                {
-                    item.kind === ResourceKind.PROJECT && <FrozenProject item={item} />
-                }
-            </Typography>
+    const navFunc = 'groupClass' in item && item.groupClass === GroupClass.ROLE ? navigateToGroupDetails : navigateTo;
+    return (
+        <Grid container alignItems='center' wrap='nowrap' spacing={16}>
+            <Grid item>{renderIcon(item)}</Grid>
+            <Grid item>
+                <Typography color='primary' style={{ width: 'auto', cursor: 'pointer' }} onClick={() => dispatch<any>(navFunc(item.uuid))}>
+                    {item.kind === ResourceKind.PROJECT || item.kind === ResourceKind.COLLECTION ? <IllegalNamingWarning name={item.name} /> : null}
+                    {item.name}
+                </Typography>
+            </Grid>
+            <Grid item>
+                <Typography variant='caption'>
+                    <FavoriteStar resourceUuid={item.uuid} />
+                    <PublicFavoriteStar resourceUuid={item.uuid} />
+                    {item.kind === ResourceKind.PROJECT && <FrozenProject item={item} />}
+                </Typography>
+            </Grid>
         </Grid>
-    </Grid>;
+    );
 };
 
-
-const FrozenProject = (props: {item: ProjectResource}) => {
+const FrozenProject = (props: { item: ProjectResource }) => {
     const [fullUsername, setFullusername] = React.useState<any>(null);
     const getFullName = React.useCallback(() => {
         if (props.item.frozenByUuid) {
             setFullusername(<UserNameFromID uuid={props.item.frozenByUuid} />);
         }
-    }, [props.item, setFullusername])
+    }, [props.item, setFullusername]);
 
     if (props.item.frozenByUuid) {
-
-        return <Tooltip onOpen={getFullName} enterDelay={500} title={<span>Project was frozen by {fullUsername}</span>}>
-            <FreezeIcon style={{ fontSize: "inherit" }}/>
-        </Tooltip>;
+        return (
+            <Tooltip onOpen={getFullName} enterDelay={500} title={<span>Project was frozen by {fullUsername}</span>}>
+                <FreezeIcon style={{ fontSize: 'inherit' }} />
+            </Tooltip>
+        );
     } else {
         return null;
     }
-}
+};
 
-export const ResourceName = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
-        return resource;
-    })((resource: GroupContentsResource & DispatchProp<any>) => renderName(resource.dispatch, resource));
+export const ResourceName = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
+    return resource;
+})((resource: GroupContentsResource & DispatchProp<any>) => renderName(resource.dispatch, resource));
+
+// const renderSelect = () => <Checkbox color='primary' />;
+const renderSelect = () => <input type='checkbox'></input>;
+
+export const ResourceSelect = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
+    return resource;
+})((resource: GroupContentsResource & DispatchProp<any>) => renderSelect());
 
-    
 const renderIcon = (item: GroupContentsResource) => {
     switch (item.kind) {
         case ResourceKind.PROJECT:
@@ -138,26 +131,28 @@ const renderIcon = (item: GroupContentsResource) => {
 };
 
 const renderDate = (date?: string) => {
-    return <Typography noWrap style={{ minWidth: '100px' }}>{formatDate(date)}</Typography>;
+    return (
+        <Typography noWrap style={{ minWidth: '100px' }}>
+            {formatDate(date)}
+        </Typography>
+    );
 };
 
-const renderWorkflowName = (item: WorkflowResource) =>
-    <Grid container alignItems="center" wrap="nowrap" spacing={16}>
-        <Grid item>
-            {renderIcon(item)}
-        </Grid>
+const renderWorkflowName = (item: WorkflowResource) => (
+    <Grid container alignItems='center' wrap='nowrap' spacing={16}>
+        <Grid item>{renderIcon(item)}</Grid>
         <Grid item>
-            <Typography color="primary" style={{ width: '100px' }}>
+            <Typography color='primary' style={{ width: '100px' }}>
                 {item.name}
             </Typography>
         </Grid>
-    </Grid>;
+    </Grid>
+);
 
-export const ResourceWorkflowName = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<WorkflowResource>(props.uuid)(state.resources);
-        return resource;
-    })(renderWorkflowName);
+export const ResourceWorkflowName = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<WorkflowResource>(props.uuid)(state.resources);
+    return resource;
+})(renderWorkflowName);
 
 const getPublicUuid = (uuidPrefix: string) => {
     return `${uuidPrefix}-tpzed-anonymouspublic`;
@@ -167,167 +162,169 @@ const resourceShare = (dispatch: Dispatch, uuidPrefix: string, ownerUuid?: strin
     const isPublic = ownerUuid === getPublicUuid(uuidPrefix);
     return (
         <div>
-            {!isPublic && uuid &&
-                <Tooltip title="Share">
+            {!isPublic && uuid && (
+                <Tooltip title='Share'>
                     <IconButton onClick={() => dispatch<any>(openSharingDialog(uuid))}>
                         <ShareIcon />
                     </IconButton>
                 </Tooltip>
-            }
+            )}
         </div>
     );
 };
 
-export const ResourceShare = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<WorkflowResource>(props.uuid)(state.resources);
-        const uuidPrefix = getUuidPrefix(state);
-        return {
-            uuid: resource ? resource.uuid : '',
-            ownerUuid: resource ? resource.ownerUuid : '',
-            uuidPrefix
-        };
-    })((props: { ownerUuid?: string, uuidPrefix: string, uuid?: string } & DispatchProp<any>) =>
-        resourceShare(props.dispatch, props.uuidPrefix, props.ownerUuid, props.uuid));
+export const ResourceShare = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<WorkflowResource>(props.uuid)(state.resources);
+    const uuidPrefix = getUuidPrefix(state);
+    return {
+        uuid: resource ? resource.uuid : '',
+        ownerUuid: resource ? resource.ownerUuid : '',
+        uuidPrefix,
+    };
+})((props: { ownerUuid?: string; uuidPrefix: string; uuid?: string } & DispatchProp<any>) =>
+    resourceShare(props.dispatch, props.uuidPrefix, props.ownerUuid, props.uuid)
+);
 
 // User Resources
 const renderFirstName = (item: { firstName: string }) => {
     return <Typography noWrap>{item.firstName}</Typography>;
 };
 
-export const ResourceFirstName = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<UserResource>(props.uuid)(state.resources);
-        return resource || { firstName: '' };
-    })(renderFirstName);
-
-const renderLastName = (item: { lastName: string }) =>
-    <Typography noWrap>{item.lastName}</Typography>;
-
-export const ResourceLastName = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<UserResource>(props.uuid)(state.resources);
-        return resource || { lastName: '' };
-    })(renderLastName);
-
-const renderFullName = (dispatch: Dispatch, item: { uuid: string, firstName: string, lastName: string }, link?: boolean) => {
-    const displayName = (item.firstName + " " + item.lastName).trim() || item.uuid;
-    return link ? <Typography noWrap
-        color="primary"
-        style={{ 'cursor': 'pointer' }}
-        onClick={() => dispatch<any>(navigateToUserProfile(item.uuid))}>
-        {displayName}
-    </Typography> :
-        <Typography noWrap>{displayName}</Typography>;
-}
+export const ResourceFirstName = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<UserResource>(props.uuid)(state.resources);
+    return resource || { firstName: '' };
+})(renderFirstName);
+
+const renderLastName = (item: { lastName: string }) => <Typography noWrap>{item.lastName}</Typography>;
+
+export const ResourceLastName = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<UserResource>(props.uuid)(state.resources);
+    return resource || { lastName: '' };
+})(renderLastName);
+
+const renderFullName = (dispatch: Dispatch, item: { uuid: string; firstName: string; lastName: string }, link?: boolean) => {
+    const displayName = (item.firstName + ' ' + item.lastName).trim() || item.uuid;
+    return link ? (
+        <Typography noWrap color='primary' style={{ cursor: 'pointer' }} onClick={() => dispatch<any>(navigateToUserProfile(item.uuid))}>
+            {displayName}
+        </Typography>
+    ) : (
+        <Typography noWrap>{displayName}</Typography>
+    );
+};
 
-export const UserResourceFullName = connect(
-    (state: RootState, props: { uuid: string, link?: boolean }) => {
-        const resource = getResource<UserResource>(props.uuid)(state.resources);
-        return { item: resource || { uuid: '', firstName: '', lastName: '' }, link: props.link };
-    })((props: { item: { uuid: string, firstName: string, lastName: string }, link?: boolean } & DispatchProp<any>) => renderFullName(props.dispatch, props.item, props.link));
+export const UserResourceFullName = connect((state: RootState, props: { uuid: string; link?: boolean }) => {
+    const resource = getResource<UserResource>(props.uuid)(state.resources);
+    return { item: resource || { uuid: '', firstName: '', lastName: '' }, link: props.link };
+})((props: { item: { uuid: string; firstName: string; lastName: string }; link?: boolean } & DispatchProp<any>) =>
+    renderFullName(props.dispatch, props.item, props.link)
+);
 
-const renderUuid = (item: { uuid: string }) =>
-    <Typography data-cy="uuid" noWrap>
+const renderUuid = (item: { uuid: string }) => (
+    <Typography data-cy='uuid' noWrap>
         {item.uuid}
-        {(item.uuid && <CopyToClipboardSnackbar value={item.uuid} />) || '-' }
-    </Typography>;
+        {(item.uuid && <CopyToClipboardSnackbar value={item.uuid} />) || '-'}
+    </Typography>
+);
 
-const renderUuidCopyIcon = (item: { uuid: string }) =>
-    <Typography data-cy="uuid" noWrap>
-        {(item.uuid && <CopyToClipboardSnackbar value={item.uuid} />) || '-' }
-    </Typography>;
+const renderUuidCopyIcon = (item: { uuid: string }) => (
+    <Typography data-cy='uuid' noWrap>
+        {(item.uuid && <CopyToClipboardSnackbar value={item.uuid} />) || '-'}
+    </Typography>
+);
 
-export const ResourceUuid = connect((state: RootState, props: { uuid: string }) => (
-    getResource<UserResource>(props.uuid)(state.resources) || { uuid: '' }
-))(renderUuid);
+export const ResourceUuid = connect((state: RootState, props: { uuid: string }) => getResource<UserResource>(props.uuid)(state.resources) || { uuid: '' })(renderUuid);
 
-const renderEmail = (item: { email: string }) =>
-    <Typography noWrap>{item.email}</Typography>;
+const renderEmail = (item: { email: string }) => <Typography noWrap>{item.email}</Typography>;
 
-export const ResourceEmail = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<UserResource>(props.uuid)(state.resources);
-        return resource || { email: '' };
-    })(renderEmail);
+export const ResourceEmail = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<UserResource>(props.uuid)(state.resources);
+    return resource || { email: '' };
+})(renderEmail);
 
 enum UserAccountStatus {
     ACTIVE = 'Active',
     INACTIVE = 'Inactive',
     SETUP = 'Setup',
-    UNKNOWN = ''
+    UNKNOWN = '',
 }
 
-const renderAccountStatus = (props: { status: UserAccountStatus }) =>
-    <Grid container alignItems="center" wrap="nowrap" spacing={8} data-cy="account-status">
+const renderAccountStatus = (props: { status: UserAccountStatus }) => (
+    <Grid container alignItems='center' wrap='nowrap' spacing={8} data-cy='account-status'>
         <Grid item>
             {(() => {
                 switch (props.status) {
                     case UserAccountStatus.ACTIVE:
-                        return <ActiveIcon style={{ color: '#4caf50', verticalAlign: "middle" }} />;
+                        return <ActiveIcon style={{ color: '#4caf50', verticalAlign: 'middle' }} />;
                     case UserAccountStatus.SETUP:
-                        return <SetupIcon style={{ color: '#2196f3', verticalAlign: "middle" }} />;
+                        return <SetupIcon style={{ color: '#2196f3', verticalAlign: 'middle' }} />;
                     case UserAccountStatus.INACTIVE:
-                        return <InactiveIcon style={{ color: '#9e9e9e', verticalAlign: "middle" }} />;
+                        return <InactiveIcon style={{ color: '#9e9e9e', verticalAlign: 'middle' }} />;
                     default:
                         return <></>;
                 }
             })()}
         </Grid>
         <Grid item>
-            <Typography noWrap>
-                {props.status}
-            </Typography>
+            <Typography noWrap>{props.status}</Typography>
         </Grid>
-    </Grid>;
+    </Grid>
+);
 
 const getUserAccountStatus = (state: RootState, props: { uuid: string }) => {
     const user = getResource<UserResource>(props.uuid)(state.resources);
     // Get membership links for all users group
     const allUsersGroupUuid = getBuiltinGroupUuid(state.auth.localCluster, BuiltinGroups.ALL);
-    const permissions = filterResources((resource: LinkResource) =>
-        resource.kind === ResourceKind.LINK &&
-        resource.linkClass === LinkClass.PERMISSION &&
-        resource.headUuid === allUsersGroupUuid &&
-        resource.tailUuid === props.uuid
+    const permissions = filterResources(
+        (resource: LinkResource) =>
+            resource.kind === ResourceKind.LINK &&
+            resource.linkClass === LinkClass.PERMISSION &&
+            resource.headUuid === allUsersGroupUuid &&
+            resource.tailUuid === props.uuid
     )(state.resources);
 
     if (user) {
-        return user.isActive ? { status: UserAccountStatus.ACTIVE } : permissions.length > 0 ? { status: UserAccountStatus.SETUP } : { status: UserAccountStatus.INACTIVE };
+        return user.isActive
+            ? { status: UserAccountStatus.ACTIVE }
+            : permissions.length > 0
+            ? { status: UserAccountStatus.SETUP }
+            : { status: UserAccountStatus.INACTIVE };
     } else {
         return { status: UserAccountStatus.UNKNOWN };
     }
-}
+};
 
-export const ResourceLinkTailAccountStatus = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const link = getResource<LinkResource>(props.uuid)(state.resources);
-        return link && link.tailKind === ResourceKind.USER ? getUserAccountStatus(state, { uuid: link.tailUuid }) : { status: UserAccountStatus.UNKNOWN };
-    })(renderAccountStatus);
+export const ResourceLinkTailAccountStatus = connect((state: RootState, props: { uuid: string }) => {
+    const link = getResource<LinkResource>(props.uuid)(state.resources);
+    return link && link.tailKind === ResourceKind.USER ? getUserAccountStatus(state, { uuid: link.tailUuid }) : { status: UserAccountStatus.UNKNOWN };
+})(renderAccountStatus);
 
 export const UserResourceAccountStatus = connect(getUserAccountStatus)(renderAccountStatus);
 
 const renderIsHidden = (props: {
-    memberLinkUuid: string,
-    permissionLinkUuid: string,
-    visible: boolean,
-    canManage: boolean,
-    setMemberIsHidden: (memberLinkUuid: string, permissionLinkUuid: string, hide: boolean) => void
+    memberLinkUuid: string;
+    permissionLinkUuid: string;
+    visible: boolean;
+    canManage: boolean;
+    setMemberIsHidden: (memberLinkUuid: string, permissionLinkUuid: string, hide: boolean) => void;
 }) => {
     if (props.memberLinkUuid) {
-        return <Checkbox
-            data-cy="user-visible-checkbox"
-            color="primary"
-            checked={props.visible}
-            disabled={!props.canManage}
-            onClick={(e) => {
-                e.stopPropagation();
-                props.setMemberIsHidden(props.memberLinkUuid, props.permissionLinkUuid, !props.visible);
-            }} />;
+        return (
+            <Checkbox
+                data-cy='user-visible-checkbox'
+                color='primary'
+                checked={props.visible}
+                disabled={!props.canManage}
+                onClick={(e) => {
+                    e.stopPropagation();
+                    props.setMemberIsHidden(props.memberLinkUuid, props.permissionLinkUuid, !props.visible);
+                }}
+            />
+        );
     } else {
         return <Typography />;
     }
-}
+};
 
 export const ResourceLinkTailIsVisible = connect(
     (state: RootState, props: { uuid: string }) => {
@@ -335,10 +332,12 @@ export const ResourceLinkTailIsVisible = connect(
         const member = getResource<Resource>(link?.tailUuid || '')(state.resources);
         const group = getResource<GroupResource>(link?.headUuid || '')(state.resources);
         const permissions = filterResources((resource: LinkResource) => {
-            return resource.linkClass === LinkClass.PERMISSION
-                && resource.headUuid === link?.tailUuid
-                && resource.tailUuid === group?.uuid
-                && resource.name === PermissionLevel.CAN_READ;
+            return (
+                resource.linkClass === LinkClass.PERMISSION &&
+                resource.headUuid === link?.tailUuid &&
+                resource.tailUuid === group?.uuid &&
+                resource.name === PermissionLevel.CAN_READ
+            );
         })(state.resources);
 
         const permissionLinkUuid = permissions.length > 0 ? permissions[0].uuid : '';
@@ -349,62 +348,58 @@ export const ResourceLinkTailIsVisible = connect(
         return member?.kind === ResourceKind.USER
             ? { memberLinkUuid: link?.uuid, permissionLinkUuid, visible: isVisible, canManage: !isBuiltin }
             : { memberLinkUuid: '', permissionLinkUuid: '', visible: false, canManage: false };
-    }, { setMemberIsHidden }
+    },
+    { setMemberIsHidden }
 )(renderIsHidden);
 
-const renderIsAdmin = (props: { uuid: string, isAdmin: boolean, toggleIsAdmin: (uuid: string) => void }) =>
+const renderIsAdmin = (props: { uuid: string; isAdmin: boolean; toggleIsAdmin: (uuid: string) => void }) => (
     <Checkbox
-        color="primary"
+        color='primary'
         checked={props.isAdmin}
         onClick={(e) => {
             e.stopPropagation();
             props.toggleIsAdmin(props.uuid);
-        }} />;
+        }}
+    />
+);
 
 export const ResourceIsAdmin = connect(
     (state: RootState, props: { uuid: string }) => {
         const resource = getResource<UserResource>(props.uuid)(state.resources);
         return resource || { isAdmin: false };
-    }, { toggleIsAdmin }
+    },
+    { toggleIsAdmin }
 )(renderIsAdmin);
 
-const renderUsername = (item: { username: string, uuid: string }) =>
-    <Typography noWrap>{item.username || item.uuid}</Typography>;
+const renderUsername = (item: { username: string; uuid: string }) => <Typography noWrap>{item.username || item.uuid}</Typography>;
 
-export const ResourceUsername = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<UserResource>(props.uuid)(state.resources);
-        return resource || { username: '', uuid: props.uuid };
-    })(renderUsername);
+export const ResourceUsername = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<UserResource>(props.uuid)(state.resources);
+    return resource || { username: '', uuid: props.uuid };
+})(renderUsername);
 
 // Virtual machine resource
 
-const renderHostname = (item: { hostname: string }) =>
-    <Typography noWrap>{item.hostname}</Typography>;
+const renderHostname = (item: { hostname: string }) => <Typography noWrap>{item.hostname}</Typography>;
 
-export const VirtualMachineHostname = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<VirtualMachinesResource>(props.uuid)(state.resources);
-        return resource || { hostname: '' };
-    })(renderHostname);
+export const VirtualMachineHostname = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<VirtualMachinesResource>(props.uuid)(state.resources);
+    return resource || { hostname: '' };
+})(renderHostname);
 
-const renderVirtualMachineLogin = (login: { user: string }) =>
-    <Typography noWrap>{login.user}</Typography>
+const renderVirtualMachineLogin = (login: { user: string }) => <Typography noWrap>{login.user}</Typography>;
 
-export const VirtualMachineLogin = connect(
-    (state: RootState, props: { linkUuid: string }) => {
-        const permission = getResource<LinkResource>(props.linkUuid)(state.resources);
-        const user = getResource<UserResource>(permission?.tailUuid || '')(state.resources);
+export const VirtualMachineLogin = connect((state: RootState, props: { linkUuid: string }) => {
+    const permission = getResource<LinkResource>(props.linkUuid)(state.resources);
+    const user = getResource<UserResource>(permission?.tailUuid || '')(state.resources);
 
-        return { user: user?.username || permission?.tailUuid || '' };
-    })(renderVirtualMachineLogin);
+    return { user: user?.username || permission?.tailUuid || '' };
+})(renderVirtualMachineLogin);
 
 // Common methods
-const renderCommonData = (data: string) =>
-    <Typography noWrap>{data}</Typography>;
+const renderCommonData = (data: string) => <Typography noWrap>{data}</Typography>;
 
-const renderCommonDate = (date: string) =>
-    <Typography noWrap>{formatDate(date)}</Typography>;
+const renderCommonDate = (date: string) => <Typography noWrap>{formatDate(date)}</Typography>;
 
 export const CommonUuid = withResourceData('uuid', renderCommonData);
 
@@ -432,188 +427,181 @@ const clusterColors = [
     ['#2196f3', '#fff'],
     ['#009688', '#fff'],
     ['#cddc39', '#fff'],
-    ['#ff9800', '#fff']
+    ['#ff9800', '#fff'],
 ];
 
 export const ResourceCluster = (props: { uuid: string }) => {
     const CLUSTER_ID_LENGTH = 5;
     const pos = props.uuid.length > CLUSTER_ID_LENGTH ? props.uuid.indexOf('-') : 5;
     const clusterId = pos >= CLUSTER_ID_LENGTH ? props.uuid.substring(0, pos) : '';
-    const ci = pos >= CLUSTER_ID_LENGTH ? (((((
-        (props.uuid.charCodeAt(0) * props.uuid.charCodeAt(1))
-        + props.uuid.charCodeAt(2))
-        * props.uuid.charCodeAt(3))
-        + props.uuid.charCodeAt(4))) % clusterColors.length) : 0;
-    return <span style={{
-        backgroundColor: clusterColors[ci][0],
-        color: clusterColors[ci][1],
-        padding: "2px 7px",
-        borderRadius: 3
-    }}>{clusterId}</span>;
+    const ci =
+        pos >= CLUSTER_ID_LENGTH
+            ? ((props.uuid.charCodeAt(0) * props.uuid.charCodeAt(1) + props.uuid.charCodeAt(2)) * props.uuid.charCodeAt(3) + props.uuid.charCodeAt(4)) %
+              clusterColors.length
+            : 0;
+    return (
+        <span
+            style={{
+                backgroundColor: clusterColors[ci][0],
+                color: clusterColors[ci][1],
+                padding: '2px 7px',
+                borderRadius: 3,
+            }}
+        >
+            {clusterId}
+        </span>
+    );
 };
 
 // Links Resources
-const renderLinkName = (item: { name: string }) =>
-    <Typography noWrap>{item.name || '-'}</Typography>;
+const renderLinkName = (item: { name: string }) => <Typography noWrap>{item.name || '-'}</Typography>;
 
-export const ResourceLinkName = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<LinkResource>(props.uuid)(state.resources);
-        return resource || { name: '' };
-    })(renderLinkName);
+export const ResourceLinkName = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<LinkResource>(props.uuid)(state.resources);
+    return resource || { name: '' };
+})(renderLinkName);
 
-const renderLinkClass = (item: { linkClass: string }) =>
-    <Typography noWrap>{item.linkClass}</Typography>;
+const renderLinkClass = (item: { linkClass: string }) => <Typography noWrap>{item.linkClass}</Typography>;
 
-export const ResourceLinkClass = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<LinkResource>(props.uuid)(state.resources);
-        return resource || { linkClass: '' };
-    })(renderLinkClass);
+export const ResourceLinkClass = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<LinkResource>(props.uuid)(state.resources);
+    return resource || { linkClass: '' };
+})(renderLinkClass);
 
 const getResourceDisplayName = (resource: Resource): string => {
-    if ((resource as UserResource).kind === ResourceKind.USER
-        && typeof (resource as UserResource).firstName !== 'undefined') {
+    if ((resource as UserResource).kind === ResourceKind.USER && typeof (resource as UserResource).firstName !== 'undefined') {
         // We can be sure the resource is UserResource
         return getUserDisplayName(resource as UserResource);
     } else {
         return (resource as GroupContentsResource).name;
     }
-}
+};
 
 const renderResourceLink = (dispatch: Dispatch, item: Resource) => {
     var displayName = getResourceDisplayName(item);
 
-    return <Typography noWrap color="primary" style={{ 'cursor': 'pointer' }} onClick={() => dispatch<any>(navigateTo(item.uuid))}>
-        {resourceLabel(item.kind, item && item.kind === ResourceKind.GROUP ? (item as GroupResource).groupClass || '' : '')}: {displayName || item.uuid}
-    </Typography>;
+    return (
+        <Typography noWrap color='primary' style={{ cursor: 'pointer' }} onClick={() => dispatch<any>(navigateTo(item.uuid))}>
+            {resourceLabel(item.kind, item && item.kind === ResourceKind.GROUP ? (item as GroupResource).groupClass || '' : '')}: {displayName || item.uuid}
+        </Typography>
+    );
 };
 
-export const ResourceLinkTail = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<LinkResource>(props.uuid)(state.resources);
-        const tailResource = getResource<Resource>(resource?.tailUuid || '')(state.resources);
+export const ResourceLinkTail = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<LinkResource>(props.uuid)(state.resources);
+    const tailResource = getResource<Resource>(resource?.tailUuid || '')(state.resources);
 
-        return {
-            item: tailResource || { uuid: resource?.tailUuid || '', kind: resource?.tailKind || ResourceKind.NONE }
-        };
-    })((props: { item: Resource } & DispatchProp<any>) =>
-        renderResourceLink(props.dispatch, props.item));
+    return {
+        item: tailResource || { uuid: resource?.tailUuid || '', kind: resource?.tailKind || ResourceKind.NONE },
+    };
+})((props: { item: Resource } & DispatchProp<any>) => renderResourceLink(props.dispatch, props.item));
 
-export const ResourceLinkHead = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<LinkResource>(props.uuid)(state.resources);
-        const headResource = getResource<Resource>(resource?.headUuid || '')(state.resources);
+export const ResourceLinkHead = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<LinkResource>(props.uuid)(state.resources);
+    const headResource = getResource<Resource>(resource?.headUuid || '')(state.resources);
 
-        return {
-            item: headResource || { uuid: resource?.headUuid || '', kind: resource?.headKind || ResourceKind.NONE }
-        };
-    })((props: { item: Resource } & DispatchProp<any>) =>
-        renderResourceLink(props.dispatch, props.item));
+    return {
+        item: headResource || { uuid: resource?.headUuid || '', kind: resource?.headKind || ResourceKind.NONE },
+    };
+})((props: { item: Resource } & DispatchProp<any>) => renderResourceLink(props.dispatch, props.item));
 
-export const ResourceLinkUuid = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<LinkResource>(props.uuid)(state.resources);
-        return resource || { uuid: '' };
-    })(renderUuid);
+export const ResourceLinkUuid = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<LinkResource>(props.uuid)(state.resources);
+    return resource || { uuid: '' };
+})(renderUuid);
 
-export const ResourceLinkHeadUuid = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const link = getResource<LinkResource>(props.uuid)(state.resources);
-        const headResource = getResource<Resource>(link?.headUuid || '')(state.resources);
+export const ResourceLinkHeadUuid = connect((state: RootState, props: { uuid: string }) => {
+    const link = getResource<LinkResource>(props.uuid)(state.resources);
+    const headResource = getResource<Resource>(link?.headUuid || '')(state.resources);
 
-        return headResource || { uuid: '' };
-    })(renderUuid);
+    return headResource || { uuid: '' };
+})(renderUuid);
 
-export const ResourceLinkTailUuid = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const link = getResource<LinkResource>(props.uuid)(state.resources);
-        const tailResource = getResource<Resource>(link?.tailUuid || '')(state.resources);
+export const ResourceLinkTailUuid = connect((state: RootState, props: { uuid: string }) => {
+    const link = getResource<LinkResource>(props.uuid)(state.resources);
+    const tailResource = getResource<Resource>(link?.tailUuid || '')(state.resources);
 
-        return tailResource || { uuid: '' };
-    })(renderUuid);
+    return tailResource || { uuid: '' };
+})(renderUuid);
 
 const renderLinkDelete = (dispatch: Dispatch, item: LinkResource, canManage: boolean) => {
     if (item.uuid) {
-        return canManage ?
+        return canManage ? (
             <Typography noWrap>
-                <IconButton data-cy="resource-delete-button" onClick={() => dispatch<any>(openRemoveGroupMemberDialog(item.uuid))}>
+                <IconButton data-cy='resource-delete-button' onClick={() => dispatch<any>(openRemoveGroupMemberDialog(item.uuid))}>
                     <RemoveIcon />
                 </IconButton>
-            </Typography> :
+            </Typography>
+        ) : (
             <Typography noWrap>
-                <IconButton disabled data-cy="resource-delete-button">
+                <IconButton disabled data-cy='resource-delete-button'>
                     <RemoveIcon />
                 </IconButton>
-            </Typography>;
+            </Typography>
+        );
     } else {
         return <Typography noWrap></Typography>;
     }
-}
+};
 
-export const ResourceLinkDelete = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const link = getResource<LinkResource>(props.uuid)(state.resources);
-        const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || '');
+export const ResourceLinkDelete = connect((state: RootState, props: { uuid: string }) => {
+    const link = getResource<LinkResource>(props.uuid)(state.resources);
+    const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || '');
 
-        return {
-            item: link || { uuid: '', kind: ResourceKind.NONE },
-            canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin,
-        };
-    })((props: { item: LinkResource, canManage: boolean } & DispatchProp<any>) =>
-        renderLinkDelete(props.dispatch, props.item, props.canManage));
+    return {
+        item: link || { uuid: '', kind: ResourceKind.NONE },
+        canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin,
+    };
+})((props: { item: LinkResource; canManage: boolean } & DispatchProp<any>) => renderLinkDelete(props.dispatch, props.item, props.canManage));
 
-export const ResourceLinkTailEmail = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const link = getResource<LinkResource>(props.uuid)(state.resources);
-        const resource = getResource<UserResource>(link?.tailUuid || '')(state.resources);
+export const ResourceLinkTailEmail = connect((state: RootState, props: { uuid: string }) => {
+    const link = getResource<LinkResource>(props.uuid)(state.resources);
+    const resource = getResource<UserResource>(link?.tailUuid || '')(state.resources);
 
-        return resource || { email: '' };
-    })(renderEmail);
+    return resource || { email: '' };
+})(renderEmail);
 
-export const ResourceLinkTailUsername = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const link = getResource<LinkResource>(props.uuid)(state.resources);
-        const resource = getResource<UserResource>(link?.tailUuid || '')(state.resources);
+export const ResourceLinkTailUsername = connect((state: RootState, props: { uuid: string }) => {
+    const link = getResource<LinkResource>(props.uuid)(state.resources);
+    const resource = getResource<UserResource>(link?.tailUuid || '')(state.resources);
 
-        return resource || { username: '' };
-    })(renderUsername);
+    return resource || { username: '' };
+})(renderUsername);
 
 const renderPermissionLevel = (dispatch: Dispatch, link: LinkResource, canManage: boolean) => {
-    return <Typography noWrap>
-        {formatPermissionLevel(link.name as PermissionLevel)}
-        {canManage ?
-            <IconButton data-cy="edit-permission-button" onClick={(event) => dispatch<any>(openPermissionEditContextMenu(event, link))}>
-                <RenameIcon />
-            </IconButton> :
-            ''
-        }
-    </Typography>;
-}
+    return (
+        <Typography noWrap>
+            {formatPermissionLevel(link.name as PermissionLevel)}
+            {canManage ? (
+                <IconButton data-cy='edit-permission-button' onClick={(event) => dispatch<any>(openPermissionEditContextMenu(event, link))}>
+                    <RenameIcon />
+                </IconButton>
+            ) : (
+                ''
+            )}
+        </Typography>
+    );
+};
 
-export const ResourceLinkHeadPermissionLevel = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const link = getResource<LinkResource>(props.uuid)(state.resources);
-        const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || '');
+export const ResourceLinkHeadPermissionLevel = connect((state: RootState, props: { uuid: string }) => {
+    const link = getResource<LinkResource>(props.uuid)(state.resources);
+    const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || '');
 
-        return {
-            link: link || { uuid: '', name: '', kind: ResourceKind.NONE },
-            canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin,
-        };
-    })((props: { link: LinkResource, canManage: boolean } & DispatchProp<any>) =>
-        renderPermissionLevel(props.dispatch, props.link, props.canManage));
+    return {
+        link: link || { uuid: '', name: '', kind: ResourceKind.NONE },
+        canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin,
+    };
+})((props: { link: LinkResource; canManage: boolean } & DispatchProp<any>) => renderPermissionLevel(props.dispatch, props.link, props.canManage));
 
-export const ResourceLinkTailPermissionLevel = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const link = getResource<LinkResource>(props.uuid)(state.resources);
-        const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || '');
+export const ResourceLinkTailPermissionLevel = connect((state: RootState, props: { uuid: string }) => {
+    const link = getResource<LinkResource>(props.uuid)(state.resources);
+    const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || '');
 
-        return {
-            link: link || { uuid: '', name: '', kind: ResourceKind.NONE },
-            canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin,
-        };
-    })((props: { link: LinkResource, canManage: boolean } & DispatchProp<any>) =>
-        renderPermissionLevel(props.dispatch, props.link, props.canManage));
+    return {
+        link: link || { uuid: '', name: '', kind: ResourceKind.NONE },
+        canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin,
+    };
+})((props: { link: LinkResource; canManage: boolean } & DispatchProp<any>) => renderPermissionLevel(props.dispatch, props.link, props.canManage));
 
 const getResourceLinkCanManage = (state: RootState, link: LinkResource) => {
     const headResource = getResource<Resource>(link.headUuid)(state.resources);
@@ -626,30 +614,29 @@ const getResourceLinkCanManage = (state: RootState, link: LinkResource) => {
         // true for now
         return true;
     }
-}
+};
 
 // Process Resources
 const resourceRunProcess = (dispatch: Dispatch, uuid: string) => {
     return (
         <div>
-            {uuid &&
-                <Tooltip title="Run process">
+            {uuid && (
+                <Tooltip title='Run process'>
                     <IconButton onClick={() => dispatch<any>(openRunProcess(uuid))}>
                         <ProcessIcon />
                     </IconButton>
-                </Tooltip>}
+                </Tooltip>
+            )}
         </div>
     );
 };
 
-export const ResourceRunProcess = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<WorkflowResource>(props.uuid)(state.resources);
-        return {
-            uuid: resource ? resource.uuid : ''
-        };
-    })((props: { uuid: string } & DispatchProp<any>) =>
-        resourceRunProcess(props.dispatch, props.uuid));
+export const ResourceRunProcess = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<WorkflowResource>(props.uuid)(state.resources);
+    return {
+        uuid: resource ? resource.uuid : '',
+    };
+})((props: { uuid: string } & DispatchProp<any>) => resourceRunProcess(props.dispatch, props.uuid));
 
 const renderWorkflowStatus = (uuidPrefix: string, ownerUuid?: string) => {
     if (ownerUuid === getPublicUuid(uuidPrefix)) {
@@ -659,353 +646,332 @@ const renderWorkflowStatus = (uuidPrefix: string, ownerUuid?: string) => {
     }
 };
 
-const renderStatus = (status: string) =>
-    <Typography noWrap style={{ width: '60px' }}>{status}</Typography>;
+const renderStatus = (status: string) => (
+    <Typography noWrap style={{ width: '60px' }}>
+        {status}
+    </Typography>
+);
 
-export const ResourceWorkflowStatus = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<WorkflowResource>(props.uuid)(state.resources);
-        const uuidPrefix = getUuidPrefix(state);
-        return {
-            ownerUuid: resource ? resource.ownerUuid : '',
-            uuidPrefix
-        };
-    })((props: { ownerUuid?: string, uuidPrefix: string }) => renderWorkflowStatus(props.uuidPrefix, props.ownerUuid));
-
-export const ResourceContainerUuid = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const process = getProcess(props.uuid)(state.resources)
-        return { uuid: process?.container?.uuid ? process?.container?.uuid : '' };
-    })((props: { uuid: string }) => renderUuid({ uuid: props.uuid }));
+export const ResourceWorkflowStatus = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<WorkflowResource>(props.uuid)(state.resources);
+    const uuidPrefix = getUuidPrefix(state);
+    return {
+        ownerUuid: resource ? resource.ownerUuid : '',
+        uuidPrefix,
+    };
+})((props: { ownerUuid?: string; uuidPrefix: string }) => renderWorkflowStatus(props.uuidPrefix, props.ownerUuid));
+
+export const ResourceContainerUuid = connect((state: RootState, props: { uuid: string }) => {
+    const process = getProcess(props.uuid)(state.resources);
+    return { uuid: process?.container?.uuid ? process?.container?.uuid : '' };
+})((props: { uuid: string }) => renderUuid({ uuid: props.uuid }));
 
 enum ColumnSelection {
     OUTPUT_UUID = 'outputUuid',
-    LOG_UUID = 'logUuid'
+    LOG_UUID = 'logUuid',
 }
 
 const renderUuidLinkWithCopyIcon = (dispatch: Dispatch, item: ProcessResource, column: string) => {
-    const selectedColumnUuid = item[column]
-    return <Grid container alignItems="center" wrap="nowrap" >
-        <Grid item>
-            {selectedColumnUuid ? 
-                <Typography color="primary" style={{ width: 'auto', cursor: 'pointer' }} noWrap 
-                    onClick={() => dispatch<any>(navigateTo(selectedColumnUuid))}>
-                    {selectedColumnUuid} 
-                </Typography> 
-            : '-' }
-        </Grid>
-        <Grid item>
-            {selectedColumnUuid && renderUuidCopyIcon({ uuid: selectedColumnUuid })}
+    const selectedColumnUuid = item[column];
+    return (
+        <Grid container alignItems='center' wrap='nowrap'>
+            <Grid item>
+                {selectedColumnUuid ? (
+                    <Typography color='primary' style={{ width: 'auto', cursor: 'pointer' }} noWrap onClick={() => dispatch<any>(navigateTo(selectedColumnUuid))}>
+                        {selectedColumnUuid}
+                    </Typography>
+                ) : (
+                    '-'
+                )}
+            </Grid>
+            <Grid item>{selectedColumnUuid && renderUuidCopyIcon({ uuid: selectedColumnUuid })}</Grid>
         </Grid>
-    </Grid>;
+    );
 };
 
-export const ResourceOutputUuid = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<ProcessResource>(props.uuid)(state.resources);
-        return resource;
-    })((process: ProcessResource & DispatchProp<any>) => renderUuidLinkWithCopyIcon(process.dispatch, process, ColumnSelection.OUTPUT_UUID));
-
-export const ResourceLogUuid = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<ProcessResource>(props.uuid)(state.resources);
-        return resource;
-    })((process: ProcessResource & DispatchProp<any>) => renderUuidLinkWithCopyIcon(process.dispatch, process, ColumnSelection.LOG_UUID));
-
-export const ResourceParentProcess = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const process = getProcess(props.uuid)(state.resources)
-        return { parentProcess: process?.containerRequest?.requestingContainerUuid || '' };
-    })((props: { parentProcess: string }) => renderUuid({uuid: props.parentProcess}));
-
-export const ResourceModifiedByUserUuid = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const process = getProcess(props.uuid)(state.resources)
-        return { userUuid: process?.containerRequest?.modifiedByUserUuid || '' };
-    })((props: { userUuid: string }) => renderUuid({uuid: props.userUuid}));
-
-    export const ResourceCreatedAtDate = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
-        return { date: resource ? resource.createdAt : '' };
-    })((props: { date: string }) => renderDate(props.date));
-    
-export const ResourceLastModifiedDate = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
-        return { date: resource ? resource.modifiedAt : '' };
-    })((props: { date: string }) => renderDate(props.date));
-
-export const ResourceTrashDate = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<TrashableResource>(props.uuid)(state.resources);
-        return { date: resource ? resource.trashAt : '' };
-    })((props: { date: string }) => renderDate(props.date));
-
-export const ResourceDeleteDate = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<TrashableResource>(props.uuid)(state.resources);
-        return { date: resource ? resource.deleteAt : '' };
-    })((props: { date: string }) => renderDate(props.date));
-
-export const renderFileSize = (fileSize?: number) =>
+export const ResourceOutputUuid = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<ProcessResource>(props.uuid)(state.resources);
+    return resource;
+})((process: ProcessResource & DispatchProp<any>) => renderUuidLinkWithCopyIcon(process.dispatch, process, ColumnSelection.OUTPUT_UUID));
+
+export const ResourceLogUuid = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<ProcessResource>(props.uuid)(state.resources);
+    return resource;
+})((process: ProcessResource & DispatchProp<any>) => renderUuidLinkWithCopyIcon(process.dispatch, process, ColumnSelection.LOG_UUID));
+
+export const ResourceParentProcess = connect((state: RootState, props: { uuid: string }) => {
+    const process = getProcess(props.uuid)(state.resources);
+    return { parentProcess: process?.containerRequest?.requestingContainerUuid || '' };
+})((props: { parentProcess: string }) => renderUuid({ uuid: props.parentProcess }));
+
+export const ResourceModifiedByUserUuid = connect((state: RootState, props: { uuid: string }) => {
+    const process = getProcess(props.uuid)(state.resources);
+    return { userUuid: process?.containerRequest?.modifiedByUserUuid || '' };
+})((props: { userUuid: string }) => renderUuid({ uuid: props.userUuid }));
+
+export const ResourceCreatedAtDate = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
+    return { date: resource ? resource.createdAt : '' };
+})((props: { date: string }) => renderDate(props.date));
+
+export const ResourceLastModifiedDate = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
+    return { date: resource ? resource.modifiedAt : '' };
+})((props: { date: string }) => renderDate(props.date));
+
+export const ResourceTrashDate = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<TrashableResource>(props.uuid)(state.resources);
+    return { date: resource ? resource.trashAt : '' };
+})((props: { date: string }) => renderDate(props.date));
+
+export const ResourceDeleteDate = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<TrashableResource>(props.uuid)(state.resources);
+    return { date: resource ? resource.deleteAt : '' };
+})((props: { date: string }) => renderDate(props.date));
+
+export const renderFileSize = (fileSize?: number) => (
     <Typography noWrap style={{ minWidth: '45px' }}>
         {formatFileSize(fileSize)}
-    </Typography>;
+    </Typography>
+);
 
-export const ResourceFileSize = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<CollectionResource>(props.uuid)(state.resources);
+export const ResourceFileSize = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<CollectionResource>(props.uuid)(state.resources);
 
-        if (resource && resource.kind !== ResourceKind.COLLECTION) {
-            return { fileSize: '' };
-        }
+    if (resource && resource.kind !== ResourceKind.COLLECTION) {
+        return { fileSize: '' };
+    }
 
-        return { fileSize: resource ? resource.fileSizeTotal : 0 };
-    })((props: { fileSize?: number }) => renderFileSize(props.fileSize));
+    return { fileSize: resource ? resource.fileSizeTotal : 0 };
+})((props: { fileSize?: number }) => renderFileSize(props.fileSize));
 
-const renderOwner = (owner: string) =>
-    <Typography noWrap>
-        {owner || '-'}
-    </Typography>;
+const renderOwner = (owner: string) => <Typography noWrap>{owner || '-'}</Typography>;
 
-export const ResourceOwner = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
-        return { owner: resource ? resource.ownerUuid : '' };
-    })((props: { owner: string }) => renderOwner(props.owner));
+export const ResourceOwner = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
+    return { owner: resource ? resource.ownerUuid : '' };
+})((props: { owner: string }) => renderOwner(props.owner));
 
-export const ResourceOwnerName = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
-        const ownerNameState = state.ownerName;
-        const ownerName = ownerNameState.find(it => it.uuid === resource!.ownerUuid);
-        return { owner: ownerName ? ownerName!.name : resource!.ownerUuid };
-    })((props: { owner: string }) => renderOwner(props.owner));
+export const ResourceOwnerName = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
+    const ownerNameState = state.ownerName;
+    const ownerName = ownerNameState.find((it) => it.uuid === resource!.ownerUuid);
+    return { owner: ownerName ? ownerName!.name : resource!.ownerUuid };
+})((props: { owner: string }) => renderOwner(props.owner));
 
-export const ResourceUUID = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<CollectionResource>(props.uuid)(state.resources);
-        return { uuid: resource ? resource.uuid : '' };
-    })((props: { uuid: string }) => renderUuid({uuid: props.uuid}));
+export const ResourceUUID = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<CollectionResource>(props.uuid)(state.resources);
+    return { uuid: resource ? resource.uuid : '' };
+})((props: { uuid: string }) => renderUuid({ uuid: props.uuid }));
 
-const renderVersion = (version: number) =>{
-    return <Typography>{version ?? '-'}</Typography>
-}
+const renderVersion = (version: number) => {
+    return <Typography>{version ?? '-'}</Typography>;
+};
 
-export const ResourceVersion = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<CollectionResource>(props.uuid)(state.resources);
-        return { version: resource ? resource.version: '' };
-    })((props: { version: number }) => renderVersion(props.version));
-    
-const renderPortableDataHash = (portableDataHash:string | null) => 
+export const ResourceVersion = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<CollectionResource>(props.uuid)(state.resources);
+    return { version: resource ? resource.version : '' };
+})((props: { version: number }) => renderVersion(props.version));
+
+const renderPortableDataHash = (portableDataHash: string | null) => (
     <Typography noWrap>
-        {portableDataHash ? <>{portableDataHash}
-        <CopyToClipboardSnackbar value={portableDataHash} /></> : '-' }
+        {portableDataHash ? (
+            <>
+                {portableDataHash}
+                <CopyToClipboardSnackbar value={portableDataHash} />
+            </>
+        ) : (
+            '-'
+        )}
     </Typography>
-    
-export const ResourcePortableDataHash = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<CollectionResource>(props.uuid)(state.resources);
-        return { portableDataHash: resource ? resource.portableDataHash : '' };    
-    })((props: { portableDataHash: string }) => renderPortableDataHash(props.portableDataHash));
-
+);
 
-const renderFileCount = (fileCount: number) =>{
-    return <Typography>{fileCount ?? '-'}</Typography>
-}
+export const ResourcePortableDataHash = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<CollectionResource>(props.uuid)(state.resources);
+    return { portableDataHash: resource ? resource.portableDataHash : '' };
+})((props: { portableDataHash: string }) => renderPortableDataHash(props.portableDataHash));
 
-export const ResourceFileCount = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<CollectionResource>(props.uuid)(state.resources);
-        return { fileCount: resource ? resource.fileCount: '' };
-    })((props: { fileCount: number }) => renderFileCount(props.fileCount));
-
-const userFromID =
-    connect(
-        (state: RootState, props: { uuid: string }) => {
-            let userFullname = '';
-            const resource = getResource<GroupContentsResource & UserResource>(props.uuid)(state.resources);
-
-            if (resource) {
-                userFullname = getUserFullname(resource as User) || (resource as GroupContentsResource).name;
-            }
-
-            return { uuid: props.uuid, userFullname };
-        });
+const renderFileCount = (fileCount: number) => {
+    return <Typography>{fileCount ?? '-'}</Typography>;
+};
 
-const ownerFromResourceId =
-    compose(
-        connect((state: RootState, props: { uuid: string }) => {
-            const childResource = getResource<GroupContentsResource & UserResource>(props.uuid)(state.resources);
-            return { uuid: childResource ? (childResource as Resource).ownerUuid : '' };
-        }),
-        userFromID
-    );
+export const ResourceFileCount = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<CollectionResource>(props.uuid)(state.resources);
+    return { fileCount: resource ? resource.fileCount : '' };
+})((props: { fileCount: number }) => renderFileCount(props.fileCount));
 
+const userFromID = connect((state: RootState, props: { uuid: string }) => {
+    let userFullname = '';
+    const resource = getResource<GroupContentsResource & UserResource>(props.uuid)(state.resources);
 
+    if (resource) {
+        userFullname = getUserFullname(resource as User) || (resource as GroupContentsResource).name;
+    }
 
+    return { uuid: props.uuid, userFullname };
+});
 
+const ownerFromResourceId = compose(
+    connect((state: RootState, props: { uuid: string }) => {
+        const childResource = getResource<GroupContentsResource & UserResource>(props.uuid)(state.resources);
+        return { uuid: childResource ? (childResource as Resource).ownerUuid : '' };
+    }),
+    userFromID
+);
 
-const _resourceWithName =
-    withStyles({}, { withTheme: true })
-        ((props: { uuid: string, userFullname: string, dispatch: Dispatch, theme: ArvadosTheme }) => {
-            const { uuid, userFullname, dispatch, theme } = props;
-            if (userFullname === '') {
-                dispatch<any>(loadResource(uuid, false));
-                return <Typography style={{ color: theme.palette.primary.main }} inline noWrap>
-                    {uuid}
-                </Typography>;
-            }
+const _resourceWithName = withStyles(
+    {},
+    { withTheme: true }
+)((props: { uuid: string; userFullname: string; dispatch: Dispatch; theme: ArvadosTheme }) => {
+    const { uuid, userFullname, dispatch, theme } = props;
+    if (userFullname === '') {
+        dispatch<any>(loadResource(uuid, false));
+        return (
+            <Typography style={{ color: theme.palette.primary.main }} inline noWrap>
+                {uuid}
+            </Typography>
+        );
+    }
 
-            return <Typography style={{ color: theme.palette.primary.main }} inline noWrap>
-                {userFullname} ({uuid})
-            </Typography>;
-        });
+    return (
+        <Typography style={{ color: theme.palette.primary.main }} inline noWrap>
+            {userFullname} ({uuid})
+        </Typography>
+    );
+});
 
 export const ResourceOwnerWithName = ownerFromResourceId(_resourceWithName);
 
 export const ResourceWithName = userFromID(_resourceWithName);
 
+export const UserNameFromID = compose(userFromID)((props: { uuid: string; displayAsText?: string; userFullname: string; dispatch: Dispatch }) => {
+    const { uuid, userFullname, dispatch } = props;
 
+    if (userFullname === '') {
+        dispatch<any>(loadResource(uuid, false));
+    }
+    return <span>{userFullname ? userFullname : uuid}</span>;
+});
 
-export const UserNameFromID =
-    compose(userFromID)(
-        (props: { uuid: string, displayAsText?: string, userFullname: string, dispatch: Dispatch }) => {
-            const { uuid, userFullname, dispatch } = props;
+export const ResponsiblePerson = compose(
+    connect((state: RootState, props: { uuid: string; parentRef: HTMLElement | null }) => {
+        let responsiblePersonName: string = '';
+        let responsiblePersonUUID: string = '';
+        let responsiblePersonProperty: string = '';
 
-            if (userFullname === '') {
-                dispatch<any>(loadResource(uuid, false));
-            }
-            return <span>
-                {userFullname ? userFullname : uuid}
-            </span>;
-        });
-
-export const ResponsiblePerson =
-    compose(
-        connect(
-            (state: RootState, props: { uuid: string, parentRef: HTMLElement | null }) => {
-                let responsiblePersonName: string = '';
-                let responsiblePersonUUID: string = '';
-                let responsiblePersonProperty: string = '';
-
-                if (state.auth.config.clusterConfig.Collections.ManagedProperties) {
-                    let index = 0;
-                    const keys = Object.keys(state.auth.config.clusterConfig.Collections.ManagedProperties);
-
-                    while (!responsiblePersonProperty && keys[index]) {
-                        const key = keys[index];
-                        if (state.auth.config.clusterConfig.Collections.ManagedProperties[key].Function === 'original_owner') {
-                            responsiblePersonProperty = key;
-                        }
-                        index++;
-                    }
+        if (state.auth.config.clusterConfig.Collections.ManagedProperties) {
+            let index = 0;
+            const keys = Object.keys(state.auth.config.clusterConfig.Collections.ManagedProperties);
+
+            while (!responsiblePersonProperty && keys[index]) {
+                const key = keys[index];
+                if (state.auth.config.clusterConfig.Collections.ManagedProperties[key].Function === 'original_owner') {
+                    responsiblePersonProperty = key;
                 }
+                index++;
+            }
+        }
 
-                let resource: Resource | undefined = getResource<GroupContentsResource & UserResource>(props.uuid)(state.resources);
+        let resource: Resource | undefined = getResource<GroupContentsResource & UserResource>(props.uuid)(state.resources);
 
-                while (resource && resource.kind !== ResourceKind.USER && responsiblePersonProperty) {
-                    responsiblePersonUUID = (resource as CollectionResource).properties[responsiblePersonProperty];
-                    resource = getResource<GroupContentsResource & UserResource>(responsiblePersonUUID)(state.resources);
-                }
+        while (resource && resource.kind !== ResourceKind.USER && responsiblePersonProperty) {
+            responsiblePersonUUID = (resource as CollectionResource).properties[responsiblePersonProperty];
+            resource = getResource<GroupContentsResource & UserResource>(responsiblePersonUUID)(state.resources);
+        }
 
-                if (resource && resource.kind === ResourceKind.USER) {
-                    responsiblePersonName = getUserFullname(resource as UserResource) || (resource as GroupContentsResource).name;
-                }
+        if (resource && resource.kind === ResourceKind.USER) {
+            responsiblePersonName = getUserFullname(resource as UserResource) || (resource as GroupContentsResource).name;
+        }
 
-                return { uuid: responsiblePersonUUID, responsiblePersonName, parentRef: props.parentRef };
-            }),
-        withStyles({}, { withTheme: true }))
-        ((props: { uuid: string | null, responsiblePersonName: string, parentRef: HTMLElement | null, theme: ArvadosTheme }) => {
-            const { uuid, responsiblePersonName, parentRef, theme } = props;
-
-            if (!uuid && parentRef) {
-                parentRef.style.display = 'none';
-                return null;
-            } else if (parentRef) {
-                parentRef.style.display = 'block';
-            }
+        return { uuid: responsiblePersonUUID, responsiblePersonName, parentRef: props.parentRef };
+    }),
+    withStyles({}, { withTheme: true })
+)((props: { uuid: string | null; responsiblePersonName: string; parentRef: HTMLElement | null; theme: ArvadosTheme }) => {
+    const { uuid, responsiblePersonName, parentRef, theme } = props;
 
-            if (!responsiblePersonName) {
-                return <Typography style={{ color: theme.palette.primary.main }} inline noWrap>
-                    {uuid}
-                </Typography>;
-            }
+    if (!uuid && parentRef) {
+        parentRef.style.display = 'none';
+        return null;
+    } else if (parentRef) {
+        parentRef.style.display = 'block';
+    }
 
-            return <Typography style={{ color: theme.palette.primary.main }} inline noWrap>
-                {responsiblePersonName} ({uuid})
-            </Typography>;
-        });
+    if (!responsiblePersonName) {
+        return (
+            <Typography style={{ color: theme.palette.primary.main }} inline noWrap>
+                {uuid}
+            </Typography>
+        );
+    }
 
-const renderType = (type: string, subtype: string) =>
-    <Typography noWrap>
-        {resourceLabel(type, subtype)}
-    </Typography>;
+    return (
+        <Typography style={{ color: theme.palette.primary.main }} inline noWrap>
+            {responsiblePersonName} ({uuid})
+        </Typography>
+    );
+});
 
-export const ResourceType = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
-        return { type: resource ? resource.kind : '', subtype: resource && resource.kind === ResourceKind.GROUP ? resource.groupClass : '' };
-    })((props: { type: string, subtype: string }) => renderType(props.type, props.subtype));
+const renderType = (type: string, subtype: string) => <Typography noWrap>{resourceLabel(type, subtype)}</Typography>;
+
+export const ResourceType = connect((state: RootState, props: { uuid: string }) => {
+    const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
+    return { type: resource ? resource.kind : '', subtype: resource && resource.kind === ResourceKind.GROUP ? resource.groupClass : '' };
+})((props: { type: string; subtype: string }) => renderType(props.type, props.subtype));
 
 export const ResourceStatus = connect((state: RootState, props: { uuid: string }) => {
     return { resource: getResource<GroupContentsResource>(props.uuid)(state.resources) };
 })((props: { resource: GroupContentsResource }) =>
-    (props.resource && props.resource.kind === ResourceKind.COLLECTION)
-        ? <CollectionStatus uuid={props.resource.uuid} />
-        : <ProcessStatus uuid={props.resource.uuid} />
+    props.resource && props.resource.kind === ResourceKind.COLLECTION ? <CollectionStatus uuid={props.resource.uuid} /> : <ProcessStatus uuid={props.resource.uuid} />
 );
 
 export const CollectionStatus = connect((state: RootState, props: { uuid: string }) => {
     return { collection: getResource<CollectionResource>(props.uuid)(state.resources) };
 })((props: { collection: CollectionResource }) =>
-    (props.collection.uuid !== props.collection.currentVersionUuid)
-        ? <Typography>version {props.collection.version}</Typography>
-        : <Typography>head version</Typography>
+    props.collection.uuid !== props.collection.currentVersionUuid ? <Typography>version {props.collection.version}</Typography> : <Typography>head version</Typography>
 );
 
-export const CollectionName = connect((state: RootState, props: { uuid: string, className?: string }) => {
+export const CollectionName = connect((state: RootState, props: { uuid: string; className?: string }) => {
     return {
-                collection: getResource<CollectionResource>(props.uuid)(state.resources),
-                uuid: props.uuid,
-                className: props.className,
-            };
-})((props: { collection: CollectionResource, uuid: string, className?: string }) =>
-        <Typography className={props.className}>{props.collection?.name || props.uuid}</Typography>
-);
+        collection: getResource<CollectionResource>(props.uuid)(state.resources),
+        uuid: props.uuid,
+        className: props.className,
+    };
+})((props: { collection: CollectionResource; uuid: string; className?: string }) => (
+    <Typography className={props.className}>{props.collection?.name || props.uuid}</Typography>
+));
 
 export const ProcessStatus = compose(
     connect((state: RootState, props: { uuid: string }) => {
         return { process: getProcess(props.uuid)(state.resources) };
     }),
-    withStyles({}, { withTheme: true }))
-    ((props: { process?: Process, theme: ArvadosTheme }) =>
-        props.process
-            ? <Chip label={getProcessStatus(props.process)}
-                style={{
-                    height: props.theme.spacing.unit * 3,
-                    width: props.theme.spacing.unit * 12,
-                    ...getProcessStatusStyles(
-                        getProcessStatus(props.process), props.theme),
-                    fontSize: '0.875rem',
-                    borderRadius: props.theme.spacing.unit * 0.625,
-                }}
-            />
-            : <Typography>-</Typography>
-        );
+    withStyles({}, { withTheme: true })
+)((props: { process?: Process; theme: ArvadosTheme }) =>
+    props.process ? (
+        <Chip
+            label={getProcessStatus(props.process)}
+            style={{
+                height: props.theme.spacing.unit * 3,
+                width: props.theme.spacing.unit * 12,
+                ...getProcessStatusStyles(getProcessStatus(props.process), props.theme),
+                fontSize: '0.875rem',
+                borderRadius: props.theme.spacing.unit * 0.625,
+            }}
+        />
+    ) : (
+        <Typography>-</Typography>
+    )
+);
 
-export const ProcessStartDate = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const process = getProcess(props.uuid)(state.resources);
-        return { date: (process && process.container) ? process.container.startedAt : '' };
-    })((props: { date: string }) => renderDate(props.date));
+export const ProcessStartDate = connect((state: RootState, props: { uuid: string }) => {
+    const process = getProcess(props.uuid)(state.resources);
+    return { date: process && process.container ? process.container.startedAt : '' };
+})((props: { date: string }) => renderDate(props.date));
 
-export const renderRunTime = (time: number) =>
+export const renderRunTime = (time: number) => (
     <Typography noWrap style={{ minWidth: '45px' }}>
         {formatTime(time, true)}
-    </Typography>;
+    </Typography>
+);
 
 interface ContainerRunTimeProps {
     process: Process;
@@ -1017,31 +983,33 @@ interface ContainerRunTimeState {
 
 export const ContainerRunTime = connect((state: RootState, props: { uuid: string }) => {
     return { process: getProcess(props.uuid)(state.resources) };
-})(class extends React.Component<ContainerRunTimeProps, ContainerRunTimeState> {
-    private timer: any;
+})(
+    class extends React.Component<ContainerRunTimeProps, ContainerRunTimeState> {
+        private timer: any;
 
-    constructor(props: ContainerRunTimeProps) {
-        super(props);
-        this.state = { runtime: this.getRuntime() };
-    }
+        constructor(props: ContainerRunTimeProps) {
+            super(props);
+            this.state = { runtime: this.getRuntime() };
+        }
 
-    getRuntime() {
-        return this.props.process ? getProcessRuntime(this.props.process) : 0;
-    }
+        getRuntime() {
+            return this.props.process ? getProcessRuntime(this.props.process) : 0;
+        }
 
-    updateRuntime() {
-        this.setState({ runtime: this.getRuntime() });
-    }
+        updateRuntime() {
+            this.setState({ runtime: this.getRuntime() });
+        }
 
-    componentDidMount() {
-        this.timer = setInterval(this.updateRuntime.bind(this), 5000);
-    }
+        componentDidMount() {
+            this.timer = setInterval(this.updateRuntime.bind(this), 5000);
+        }
 
-    componentWillUnmount() {
-        clearInterval(this.timer);
-    }
+        componentWillUnmount() {
+            clearInterval(this.timer);
+        }
 
-    render() {
-        return this.props.process ? renderRunTime(this.state.runtime) : <Typography>-</Typography>;
+        render() {
+            return this.props.process ? renderRunTime(this.state.runtime) : <Typography>-</Typography>;
+        }
     }
-});
+);
index 684fd448443b7102042b3527cebbb5d001ecd3ae..b4019e1e4704b4f10a21495b295656fd1fd6a648 100644 (file)
@@ -3,12 +3,12 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import React from 'react';
-import withStyles from "@material-ui/core/styles/withStyles";
+import withStyles from '@material-ui/core/styles/withStyles';
 import { DispatchProp, connect } from 'react-redux';
 import { RouteComponentProps } from 'react-router';
-import { StyleRulesCallback, WithStyles } from "@material-ui/core";
+import { StyleRulesCallback, WithStyles } from '@material-ui/core';
 
-import { DataExplorer } from "views-components/data-explorer/data-explorer";
+import { DataExplorer } from 'views-components/data-explorer/data-explorer';
 import { DataColumns } from 'components/data-table/data-table';
 import { RootState } from 'store/store';
 import { DataTableFilterItem } from 'components/data-table-filters/data-table-filters';
@@ -16,6 +16,7 @@ import { ContainerRequestState } from 'models/container-request';
 import { SortDirection } from 'components/data-table/data-column';
 import { ResourceKind, Resource } from 'models/resource';
 import {
+    ResourceSelect,
     ResourceName,
     ProcessStatus as ResourceStatus,
     ResourceType,
@@ -37,61 +38,53 @@ import {
     ResourceDeleteDate,
 } from 'views-components/data-explorer/renderers';
 import { ProjectIcon } from 'components/icon/icon';
-import {
-    ResourcesState,
-    getResource
-} from 'store/resources/resources';
+import { ResourcesState, getResource } from 'store/resources/resources';
 import { loadDetailsPanel } from 'store/details-panel/details-panel-action';
-import {
-    openContextMenu,
-    resourceUuidToContextMenuKind
-} from 'store/context-menu/context-menu-actions';
+import { openContextMenu, resourceUuidToContextMenuKind } from 'store/context-menu/context-menu-actions';
 import { navigateTo } from 'store/navigation/navigation-action';
 import { getProperty } from 'store/properties/properties';
 import { PROJECT_PANEL_CURRENT_UUID } from 'store/project-panel/project-panel-action';
-import { ArvadosTheme } from "common/custom-theme";
+import { ArvadosTheme } from 'common/custom-theme';
 import { createTree } from 'models/tree';
-import {
-    getInitialResourceTypeFilters,
-    getInitialProcessStatusFilters
-} from 'store/resource-type-filters/resource-type-filters';
+import { getInitialResourceTypeFilters, getInitialProcessStatusFilters } from 'store/resource-type-filters/resource-type-filters';
 import { GroupContentsResource } from 'services/groups-service/groups-service';
 import { GroupClass, GroupResource } from 'models/group';
 import { CollectionResource } from 'models/collection';
 import { resourceIsFrozen } from 'common/frozen-resources';
 import { ProjectResource } from 'models/project';
 
-type CssRules = 'root' | "button";
+type CssRules = 'root' | 'button';
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     root: {
         width: '100%',
     },
     button: {
-        marginLeft: theme.spacing.unit
+        marginLeft: theme.spacing.unit,
     },
 });
 
 export enum ProjectPanelColumnNames {
-    NAME = "Name",
-    STATUS = "Status",
-    TYPE = "Type",
-    OWNER = "Owner",
-    PORTABLE_DATA_HASH = "Portable Data Hash",
-    FILE_SIZE = "File Size",
-    FILE_COUNT = "File Count",
-    UUID = "UUID",
-    CONTAINER_UUID = "Container UUID",
-    RUNTIME = "Runtime",
-    OUTPUT_UUID = "Output UUID",
-    LOG_UUID = "Log UUID",
+    SELECT = '',
+    NAME = 'Name',
+    STATUS = 'Status',
+    TYPE = 'Type',
+    OWNER = 'Owner',
+    PORTABLE_DATA_HASH = 'Portable Data Hash',
+    FILE_SIZE = 'File Size',
+    FILE_COUNT = 'File Count',
+    UUID = 'UUID',
+    CONTAINER_UUID = 'Container UUID',
+    RUNTIME = 'Runtime',
+    OUTPUT_UUID = 'Output UUID',
+    LOG_UUID = 'Log UUID',
     PARENT_PROCESS = 'Parent Process UUID',
     MODIFIED_BY_USER_UUID = 'Modified by User UUID',
-    VERSION = "Version",
-    CREATED_AT = "Date Created",
-    LAST_MODIFIED = "Last Modified",
-    TRASH_AT = "Trash at",
-    DELETE_AT = "Delete at",
+    VERSION = 'Version',
+    CREATED_AT = 'Date Created',
+    LAST_MODIFIED = 'Last Modified',
+    TRASH_AT = 'Trash at',
+    DELETE_AT = 'Delete at',
 }
 
 export interface ProjectPanelFilter extends DataTableFilterItem {
@@ -99,13 +92,20 @@ export interface ProjectPanelFilter extends DataTableFilterItem {
 }
 
 export const projectPanelColumns: DataColumns<string, ProjectResource> = [
+    {
+        name: ProjectPanelColumnNames.SELECT,
+        selected: true,
+        configurable: false,
+        filters: createTree(),
+        render: (uuid) => <ResourceSelect uuid={uuid} />,
+    },
     {
         name: ProjectPanelColumnNames.NAME,
         selected: true,
         configurable: true,
-        sort: {direction: SortDirection.NONE, field: "name"},
+        sort: { direction: SortDirection.NONE, field: 'name' },
         filters: createTree(),
-        render: uuid => <ResourceName uuid={uuid} />
+        render: (uuid) => <ResourceName uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.STATUS,
@@ -113,140 +113,136 @@ export const projectPanelColumns: DataColumns<string, ProjectResource> = [
         configurable: true,
         mutuallyExclusiveFilters: true,
         filters: getInitialProcessStatusFilters(),
-        render: uuid => <ResourceStatus uuid={uuid} />,
+        render: (uuid) => <ResourceStatus uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.TYPE,
         selected: true,
         configurable: true,
         filters: getInitialResourceTypeFilters(),
-        render: uuid => <ResourceType uuid={uuid} />
+        render: (uuid) => <ResourceType uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.OWNER,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceOwnerWithName uuid={uuid} />
+        render: (uuid) => <ResourceOwnerWithName uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.PORTABLE_DATA_HASH,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourcePortableDataHash uuid={uuid} />
+        render: (uuid) => <ResourcePortableDataHash uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.FILE_SIZE,
         selected: true,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceFileSize uuid={uuid} />
+        render: (uuid) => <ResourceFileSize uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.FILE_COUNT,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceFileCount uuid={uuid} />
+        render: (uuid) => <ResourceFileCount uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.UUID,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceUUID uuid={uuid} />
+        render: (uuid) => <ResourceUUID uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.CONTAINER_UUID,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceContainerUuid uuid={uuid} />
+        render: (uuid) => <ResourceContainerUuid uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.RUNTIME,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ContainerRunTime uuid={uuid} />
+        render: (uuid) => <ContainerRunTime uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.OUTPUT_UUID,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceOutputUuid uuid={uuid} />
+        render: (uuid) => <ResourceOutputUuid uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.LOG_UUID,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceLogUuid uuid={uuid} />
+        render: (uuid) => <ResourceLogUuid uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.PARENT_PROCESS,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceParentProcess uuid={uuid} />
+        render: (uuid) => <ResourceParentProcess uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.MODIFIED_BY_USER_UUID,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceModifiedByUserUuid uuid={uuid} />
+        render: (uuid) => <ResourceModifiedByUserUuid uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.VERSION,
         selected: false,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceVersion uuid={uuid} />
+        render: (uuid) => <ResourceVersion uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.CREATED_AT,
         selected: false,
         configurable: true,
-        sort: {direction: SortDirection.NONE, field: "createdAt"},
+        sort: { direction: SortDirection.NONE, field: 'createdAt' },
         filters: createTree(),
-        render: uuid => <ResourceCreatedAtDate uuid={uuid} />
+        render: (uuid) => <ResourceCreatedAtDate uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.LAST_MODIFIED,
         selected: true,
         configurable: true,
-        sort: {direction: SortDirection.DESC, field: "modifiedAt"},
+        sort: { direction: SortDirection.DESC, field: 'modifiedAt' },
         filters: createTree(),
-        render: uuid => <ResourceLastModifiedDate uuid={uuid} />
+        render: (uuid) => <ResourceLastModifiedDate uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.TRASH_AT,
         selected: false,
         configurable: true,
-        sort: {direction: SortDirection.NONE, field: "trashAt"},
+        sort: { direction: SortDirection.NONE, field: 'trashAt' },
         filters: createTree(),
-        render: uuid => <ResourceTrashDate uuid={uuid} />
+        render: (uuid) => <ResourceTrashDate uuid={uuid} />,
     },
     {
         name: ProjectPanelColumnNames.DELETE_AT,
         selected: false,
         configurable: true,
-        sort: {direction: SortDirection.NONE, field: "deleteAt"},
+        sort: { direction: SortDirection.NONE, field: 'deleteAt' },
         filters: createTree(),
-        render: uuid => <ResourceDeleteDate uuid={uuid} />
+        render: (uuid) => <ResourceDeleteDate uuid={uuid} />,
     },
-
 ];
 
-export const PROJECT_PANEL_ID = "projectPanel";
+export const PROJECT_PANEL_ID = 'projectPanel';
 
-const DEFAULT_VIEW_MESSAGES = [
-    'Your project is empty.',
-    'Please create a project or create a collection and upload a data.',
-];
+const DEFAULT_VIEW_MESSAGES = ['Your project is empty.', 'Please create a project or create a collection and upload a data.'];
 
 interface ProjectPanelDataProps {
     currentItemId: string;
@@ -256,36 +252,36 @@ interface ProjectPanelDataProps {
     dataExplorerItems: any;
 }
 
-type ProjectPanelProps = ProjectPanelDataProps & DispatchProp
-    & WithStyles<CssRules> & RouteComponentProps<{ id: string }>;
-
+type ProjectPanelProps = ProjectPanelDataProps & DispatchProp & WithStyles<CssRules> & RouteComponentProps<{ id: string }>;
 
 export const ProjectPanel = withStyles(styles)(
     connect((state: RootState) => ({
         currentItemId: getProperty(PROJECT_PANEL_CURRENT_UUID)(state.properties),
         resources: state.resources,
-        userUuid: state.auth.user!.uuid
+        userUuid: state.auth.user!.uuid,
     }))(
         class extends React.Component<ProjectPanelProps> {
             render() {
                 const { classes } = this.props;
 
-                return <div data-cy='project-panel' className={classes.root}>
-                    <DataExplorer
-                        id={PROJECT_PANEL_ID}
-                        onRowClick={this.handleRowClick}
-                        onRowDoubleClick={this.handleRowDoubleClick}
-                        onContextMenu={this.handleContextMenu}
-                        contextMenuColumn={true}
-                        defaultViewIcon={ProjectIcon}
-                        defaultViewMessages={DEFAULT_VIEW_MESSAGES}
-                    />
-                </div>;
+                return (
+                    <div data-cy='project-panel' className={classes.root}>
+                        <DataExplorer
+                            id={PROJECT_PANEL_ID}
+                            onRowClick={this.handleRowClick}
+                            onRowDoubleClick={this.handleRowDoubleClick}
+                            onContextMenu={this.handleContextMenu}
+                            contextMenuColumn={true}
+                            defaultViewIcon={ProjectIcon}
+                            defaultViewMessages={DEFAULT_VIEW_MESSAGES}
+                        />
+                    </div>
+                );
             }
 
             isCurrentItemChild = (resource: Resource) => {
                 return resource.ownerUuid === this.props.currentItemId;
-            }
+            };
 
             handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
                 const { resources, isAdmin } = this.props;
@@ -299,31 +295,32 @@ export const ProjectPanel = withStyles(styles)(
 
                 const menuKind = this.props.dispatch<any>(resourceUuidToContextMenuKind(resourceUuid, readonly));
                 if (menuKind && resource) {
-                    this.props.dispatch<any>(openContextMenu(event, {
-                        name: resource.name,
-                        uuid: resource.uuid,
-                        ownerUuid: resource.ownerUuid,
-                        isTrashed: ('isTrashed' in resource) ? resource.isTrashed : false,
-                        kind: resource.kind,
-                        menuKind,
-                        isAdmin,
-                        isFrozen: resourceIsFrozen(resource, resources),
-                        description: resource.description,
-                        storageClassesDesired: (resource as CollectionResource).storageClassesDesired,
-                        properties: ('properties' in resource) ? resource.properties : {},
-                    }));
+                    this.props.dispatch<any>(
+                        openContextMenu(event, {
+                            name: resource.name,
+                            uuid: resource.uuid,
+                            ownerUuid: resource.ownerUuid,
+                            isTrashed: 'isTrashed' in resource ? resource.isTrashed : false,
+                            kind: resource.kind,
+                            menuKind,
+                            isAdmin,
+                            isFrozen: resourceIsFrozen(resource, resources),
+                            description: resource.description,
+                            storageClassesDesired: (resource as CollectionResource).storageClassesDesired,
+                            properties: 'properties' in resource ? resource.properties : {},
+                        })
+                    );
                 }
                 this.props.dispatch<any>(loadDetailsPanel(resourceUuid));
-            }
+            };
 
             handleRowDoubleClick = (uuid: string) => {
                 this.props.dispatch<any>(navigateTo(uuid));
-            }
+            };
 
             handleRowClick = (uuid: string) => {
                 this.props.dispatch<any>(loadDetailsPanel(uuid));
-            }
-
+            };
         }
     )
 );