Merge branch 'master' into 14093-data-explorer-table-cell-width
authorJanicki Artur <artur.janicki@contractors.roche.com>
Thu, 6 Sep 2018 07:09:54 +0000 (09:09 +0200)
committerJanicki Artur <artur.janicki@contractors.roche.com>
Thu, 6 Sep 2018 07:09:54 +0000 (09:09 +0200)
refs #14093

Arvados-DCO-1.1-Signed-off-by: Janicki Artur <artur.janicki@contractors.roche.com>

1  2 
src/components/data-explorer/data-explorer.tsx
src/components/data-table/data-table.tsx
src/views/favorite-panel/favorite-panel.tsx
src/views/project-panel/project-panel.tsx
src/views/trash-panel/trash-panel.tsx

index 5faaabcb79d958426e5156893a0de76f6f3e7059,1535fde2b67a8097df409db233d89d3ec1ec7903..52ffd2e774fdc5aea5744150121074da7214d69b
@@@ -11,10 -11,8 +11,8 @@@ import { DataColumn, SortDirection } fr
  import { DataTableFilterItem } from '../data-table-filters/data-table-filters';
  import { SearchInput } from '../search-input/search-input';
  import { ArvadosTheme } from "~/common/custom-theme";
- import { DefaultView } from '../default-view/default-view';
- import { IconType } from '../icon/icon';
  
- type CssRules = 'searchBox' | "toolbar" | 'defaultRoot' | 'defaultMessage' | 'defaultIcon';
+ type CssRules = 'searchBox' | "toolbar";
  
  const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
      searchBox: {
      toolbar: {
          paddingTop: theme.spacing.unit * 2
      },
-     defaultRoot: {
-         position: 'absolute',
-         width: '80%',
-         left: '50%',
-         top: '50%',
-         transform: 'translate(-50%, -50%)'
-     },
-     defaultMessage: {
-         fontSize: '1.75rem',
-     },
-     defaultIcon: {
-         fontSize: '6rem'
-     }
  });
  
  interface DataExplorerDataProps<T> {
@@@ -46,9 -31,8 +31,8 @@@
      rowsPerPage: number;
      rowsPerPageOptions: number[];
      page: number;
-     defaultIcon: IconType;
-     defaultMessages: string[];
      contextMenuColumn: boolean;
+     dataTableDefaultView?: React.ReactNode;
  }
  
  interface DataExplorerActionProps<T> {
@@@ -78,54 -62,46 +62,46 @@@ export const DataExplorer = withStyles(
              const {
                  columns, onContextMenu, onFiltersChange, onSortToggle, extractKey,
                  rowsPerPage, rowsPerPageOptions, onColumnToggle, searchValue, onSearch,
-                 items, itemsAvailable, onRowClick, onRowDoubleClick, defaultIcon, defaultMessages, classes
+                 items, itemsAvailable, onRowClick, onRowDoubleClick, classes,
+                 dataTableDefaultView
              } = this.props;
-             return <div>
-                 { items.length > 0 ? (
-                     <Paper>
-                         <Toolbar className={classes.toolbar}>
-                             <Grid container justify="space-between" wrap="nowrap" alignItems="center">
-                                 <div className={classes.searchBox}>
-                                     <SearchInput
-                                         value={searchValue}
-                                         onSearch={onSearch}/>
-                                 </div>
-                                 <ColumnSelector
-                                     columns={columns}
-                                     onColumnToggle={onColumnToggle}/>
-                             </Grid>
-                         </Toolbar>
-                         <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}/>
-                         <Toolbar>
-                             <Grid container justify="flex-end">
-                                 <TablePagination
-                                     count={itemsAvailable}
-                                     rowsPerPage={rowsPerPage}
-                                     rowsPerPageOptions={rowsPerPageOptions}
-                                     page={this.props.page}
-                                     onChangePage={this.changePage}
-                                     onChangeRowsPerPage={this.changeRowsPerPage}
-                                     component="div" />
-                             </Grid>
-                         </Toolbar>
-                     </Paper>
-                 ) : (
-                     <DefaultView
-                         classRoot={classes.defaultRoot}
-                         icon={defaultIcon}
-                         classIcon={classes.defaultIcon}
-                         messages={defaultMessages}
-                         classMessage={classes.defaultMessage} />
-                 )}
-             </div>;
+             return <Paper>
+                 <Toolbar className={classes.toolbar}>
+                     <Grid container justify="space-between" wrap="nowrap" alignItems="center">
+                         <div className={classes.searchBox}>
+                             <SearchInput
+                                 value={searchValue}
+                                 onSearch={onSearch} />
+                         </div>
+                         <ColumnSelector
+                             columns={columns}
+                             onColumnToggle={onColumnToggle} />
+                     </Grid>
+                 </Toolbar>
+                 <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}
+                     defaultView={dataTableDefaultView}
+                 />
+                 <Toolbar>
+                     <Grid container justify="flex-end">
+                         <TablePagination
+                             count={itemsAvailable}
+                             rowsPerPage={rowsPerPage}
+                             rowsPerPageOptions={rowsPerPageOptions}
+                             page={this.props.page}
+                             onChangePage={this.changePage}
+                             onChangeRowsPerPage={this.changeRowsPerPage}
+                             component="div" />
+                     </Grid>
+                 </Toolbar>
+             </Paper>;
          }
  
          changePage = (event: React.MouseEvent<HTMLButtonElement>, page: number) => {
          renderContextMenuTrigger = (item: T) =>
              <Grid container justify="flex-end">
                  <IconButton onClick={event => this.props.onContextMenu(event, item)}>
-                     <MoreVertIcon/>
+                     <MoreVertIcon />
                  </IconButton>
              </Grid>
  
              sortDirection: SortDirection.NONE,
              filters: [],
              key: "context-actions",
 -            render: this.renderContextMenuTrigger,
 -            width: "auto"
 +            render: this.renderContextMenuTrigger
          };
      }
  );
index 1d208d7590536f93412fbb564fcb27cd62e939d9,db7b484a09660241e9170c9b83e31ee8899a6f69..0b3819ac8072698058185a8c67c82264921eda96
@@@ -5,7 -5,8 +5,8 @@@
  import * as React from 'react';
  import { Table, TableBody, TableRow, TableCell, TableHead, TableSortLabel, StyleRulesCallback, Theme, WithStyles, withStyles } from '@material-ui/core';
  import { DataColumn, SortDirection } from './data-column';
- import { DataTableFilters,  DataTableFilterItem } from "../data-table-filters/data-table-filters";
+ import { DataTableFilters, DataTableFilterItem } from "../data-table-filters/data-table-filters";
+ import { DataTableDefaultView } from '../data-table-default-view/data-table-default-view';
  
  export type DataColumns<T, F extends DataTableFilterItem = DataTableFilterItem> = Array<DataColumn<T, F>>;
  
@@@ -18,15 -19,19 +19,19 @@@ export interface DataTableDataProps<T> 
      onSortToggle: (column: DataColumn<T>) => void;
      onFiltersChange: (filters: DataTableFilterItem[], column: DataColumn<T>) => void;
      extractKey?: (item: T) => React.Key;
+     defaultView?: React.ReactNode;
  }
  
- type CssRules = "tableBody" | "tableContainer" | "noItemsInfo" | 'tableCell';
 -type CssRules = "tableBody" | "root" | "content" | "noItemsInfo";
++type CssRules = "tableBody" | "root" | "content" | "noItemsInfo" | 'tableCell';
  
  const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
-     tableContainer: {
+     root: {
          overflowX: 'auto',
          overflowY: 'hidden'
      },
+     content: {
+         display: 'inline-block',
+     },
      tableBody: {
          background: theme.palette.background.paper
      },
@@@ -34,9 -39,6 +39,9 @@@
          textAlign: "center",
          padding: theme.spacing.unit
      },
 +    tableCell: {
 +        wordWrap: 'break-word'
 +    }
  });
  
  type DataTableProps<T> = DataTableDataProps<T> & WithStyles<CssRules>;
@@@ -45,25 -47,33 +50,33 @@@ export const DataTable = withStyles(sty
      class Component<T> extends React.Component<DataTableProps<T>> {
          render() {
              const { items, classes } = this.props;
-             return <div
-                 className={classes.tableContainer}>
-                 <Table>
-                     <TableHead>
-                         <TableRow>
-                             {this.mapVisibleColumns(this.renderHeadCell)}
-                         </TableRow>
-                     </TableHead>
-                     <TableBody className={classes.tableBody}>
-                         {items.map(this.renderBodyRow)}
-                     </TableBody>
-                 </Table>
+             return <div className={classes.root}>
+                 <div className={classes.content}>
+                     <Table>
+                         <TableHead>
+                             <TableRow>
+                                 {this.mapVisibleColumns(this.renderHeadCell)}
+                             </TableRow>
+                         </TableHead>
+                         <TableBody className={classes.tableBody}>
+                             {items.map(this.renderBodyRow)}
+                         </TableBody>
+                     </Table>
+                     {items.length === 0 && this.renderNoItemsPlaceholder()}
+                 </div>
              </div>;
          }
  
+         renderNoItemsPlaceholder = () => {
+             return this.props.defaultView
+                 ? this.props.defaultView
+                 : <DataTableDefaultView />;
+         }
          renderHeadCell = (column: DataColumn<T>, index: number) => {
              const { name, key, renderHeader, filters, sortDirection } = column;
              const { onSortToggle, onFiltersChange } = this.props;
 -            return <TableCell key={key || index} style={{ width: column.width, minWidth: column.width }}>
 +            return <TableCell key={key || index}>
                  {renderHeader ?
                      renderHeader() :
                      filters.length > 0
          }
  
          renderBodyRow = (item: T, index: number) => {
 -            const { onRowClick, onRowDoubleClick, extractKey } = this.props;
 +            const { onRowClick, onRowDoubleClick, extractKey, classes } = 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) }>
+                 onDoubleClick={event => onRowDoubleClick && onRowDoubleClick(event, item)}>
                  {this.mapVisibleColumns((column, index) => (
 -                    <TableCell key={column.key || index}>
 +                    <TableCell key={column.key || index} className={classes.tableCell}>
                          {column.render(item)}
                      </TableCell>
                  ))}
index 811546187563c805b1569f5c449da2f1a9a8d6ce,9f35ecd6c27e26d5159656eafb369993bda33ad9..73849562dad12f34c4153188f0d9e6cd5ce8180c
@@@ -28,6 -28,10 +28,10 @@@ import { openContextMenu, resourceKindT
  import { loadDetailsPanel } from '~/store/details-panel/details-panel-action';
  import { navigateTo } from '~/store/navigation/navigation-action';
  import { ContainerRequestState } from "~/models/container-request";
+ import { FavoritesState } from '../../store/favorites/favorites-reducer';
+ import { RootState } from '~/store/store';
+ import { PanelDefaultView } from '~/components/panel-default-view/panel-default-view';
+ import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
  
  type CssRules = "toolbar" | "button";
  
@@@ -61,14 -65,16 +65,14 @@@ export const favoritePanelColumns: Data
          configurable: true,
          sortDirection: SortDirection.ASC,
          filters: [],
 -        render: uuid => <ResourceName uuid={uuid} />,
 -        width: "450px"
 +        render: uuid => <ResourceName uuid={uuid} />
      },
      {
          name: "Status",
          selected: true,
          configurable: true,
          filters: [],
 -        render: uuid => <ProcessStatus uuid={uuid} />,
 -        width: "75px"
 +        render: uuid => <ProcessStatus uuid={uuid} />
      },
      {
          name: FavoritePanelColumnNames.TYPE,
                  type: ResourceKind.PROJECT
              }
          ],
 -        render: uuid => <ResourceType uuid={uuid} />,
 -        width: "125px"
 +        render: uuid => <ResourceType uuid={uuid} />
      },
      {
          name: FavoritePanelColumnNames.OWNER,
          selected: true,
          configurable: true,
          filters: [],
 -        render: uuid => <ResourceOwner uuid={uuid} />,
 -        width: "200px"
 +        render: uuid => <ResourceOwner uuid={uuid} />
      },
      {
          name: FavoritePanelColumnNames.FILE_SIZE,
          selected: true,
          configurable: true,
          filters: [],
 -        render: uuid => <ResourceFileSize uuid={uuid} />,
 -        width: "50px"
 +        render: uuid => <ResourceFileSize uuid={uuid} />
      },
      {
          name: FavoritePanelColumnNames.LAST_MODIFIED,
          configurable: true,
          sortDirection: SortDirection.NONE,
          filters: [],
 -        render: uuid => <ResourceLastModifiedDate uuid={uuid} />,
 -        width: "150px"
 +        render: uuid => <ResourceLastModifiedDate uuid={uuid} />
      }
  ];
  
  interface FavoritePanelDataProps {
-     currentItemId: string;
+     favorites: FavoritesState;
  }
  
  interface FavoritePanelActionProps {
      onDialogOpen: (ownerUuid: string) => void;
      onItemDoubleClick: (item: string) => void;
  }
+ const mapStateToProps = ({ favorites }: RootState): FavoritePanelDataProps => ({
+     favorites
+ });
  
  const mapDispatchToProps = (dispatch: Dispatch): FavoritePanelActionProps => ({
      onContextMenu: (event, resourceUuid) => {
@@@ -154,17 -167,26 +161,26 @@@ type FavoritePanelProps = FavoritePanel
      & WithStyles<CssRules> & RouteComponentProps<{ id: string }>;
  
  export const FavoritePanel = withStyles(styles)(
-     connect(undefined, mapDispatchToProps)(
+     connect(mapStateToProps, mapDispatchToProps)(
          class extends React.Component<FavoritePanelProps> {
              render() {
-                 return <DataExplorer
-                     id={FAVORITE_PANEL_ID}
-                     onRowClick={this.props.onItemClick}
-                     onRowDoubleClick={this.props.onItemDoubleClick}
-                     onContextMenu={this.props.onContextMenu}
-                     defaultIcon={FavoriteIcon}
-                     defaultMessages={['Your favorites list is empty.']}
-                     contextMenuColumn={true}/>;
+                 return this.hasAnyFavorites()
+                     ? <DataExplorer
+                         id={FAVORITE_PANEL_ID}
+                         onRowClick={this.props.onItemClick}
+                         onRowDoubleClick={this.props.onItemDoubleClick}
+                         onContextMenu={this.props.onContextMenu}
+                         contextMenuColumn={true}
+                         dataTableDefaultView={<DataTableDefaultView icon={FavoriteIcon}/>} />
+                     : <PanelDefaultView
+                         icon={FavoriteIcon}
+                         messages={['Your favorites list is empty.']} />;
+             }
+             hasAnyFavorites = () => {
+                 return Object
+                     .keys(this.props.favorites)
+                     .find(uuid => this.props.favorites[uuid]);
              }
          }
      )
index 787dc670d749c1967adb1d533f94ec99044940d8,aa361bc9cb47431acaed8dfc8967e513d43abbca..63aedaddeb4e17a62cfd318a12cdea66114c87e2
@@@ -12,7 -12,7 +12,7 @@@ import { RootState } from '~/store/stor
  import { DataTableFilterItem } from '~/components/data-table-filters/data-table-filters';
  import { ContainerRequestState } from '~/models/container-request';
  import { SortDirection } from '~/components/data-table/data-column';
- import { ResourceKind } from '~/models/resource';
+ import { ResourceKind, Resource } from '~/models/resource';
  import { resourceLabel } from '~/common/labels';
  import { ArvadosTheme } from '~/common/custom-theme';
  import { ResourceFileSize, ResourceLastModifiedDate, ProcessStatus, ResourceType, ResourceOwner } from '~/views-components/data-explorer/renderers';
@@@ -25,8 -25,11 +25,11 @@@ import { ProjectResource } from '~/mode
  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 { openCollectionCreateDialog } from '../../store/collections/collection-create-actions';
+ import { openCollectionCreateDialog } from '~/store/collections/collection-create-actions';
  import { openProjectCreateDialog } from '~/store/projects/project-create-actions';
+ import { filterResources } from '~/store/resources/resources';
+ import { PanelDefaultView } from '~/components/panel-default-view/panel-default-view';
+ import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
  
  type CssRules = 'root' | "toolbar" | "button";
  
@@@ -65,7 -68,8 +68,7 @@@ export const projectPanelColumns: DataC
          configurable: true,
          sortDirection: SortDirection.ASC,
          filters: [],
 -        render: uuid => <ResourceName uuid={uuid} />,
 -        width: "450px"
 +        render: uuid => <ResourceName uuid={uuid} />
      },
      {
          name: "Status",
@@@ -73,6 -77,7 +76,6 @@@
          configurable: true,
          filters: [],
          render: uuid => <ProcessStatus uuid={uuid} />,
 -        width: "75px"
      },
      {
          name: ProjectPanelColumnNames.TYPE,
                  type: ResourceKind.PROJECT
              }
          ],
 -        render: uuid => <ResourceType uuid={uuid} />,
 -        width: "125px"
 +        render: uuid => <ResourceType uuid={uuid} />
      },
      {
          name: ProjectPanelColumnNames.OWNER,
          selected: true,
          configurable: true,
          filters: [],
 -        render: uuid => <ResourceOwner uuid={uuid} />,
 -        width: "200px"
 +        render: uuid => <ResourceOwner uuid={uuid} />
      },
      {
          name: ProjectPanelColumnNames.FILE_SIZE,
          selected: true,
          configurable: true,
          filters: [],
 -        render: uuid => <ResourceFileSize uuid={uuid} />,
 -        width: "50px"
 +        render: uuid => <ResourceFileSize uuid={uuid} />
      },
      {
          name: ProjectPanelColumnNames.LAST_MODIFIED,
          configurable: true,
          sortDirection: SortDirection.NONE,
          filters: [],
 -        render: uuid => <ResourceLastModifiedDate uuid={uuid} />,
 -        width: "150px"
 +        render: uuid => <ResourceLastModifiedDate uuid={uuid} />
      }
  ];
  
@@@ -151,17 -160,31 +154,31 @@@ export const ProjectPanel = withStyles(
                              New project
                          </Button>
                      </div>
-                     <DataExplorer
-                         id={PROJECT_PANEL_ID}
-                         onRowClick={this.handleRowClick}
-                         onRowDoubleClick={this.handleRowDoubleClick}
-                         onContextMenu={this.handleContextMenu}
-                         defaultIcon={ProjectIcon}
-                         defaultMessages={['Your project is empty.', 'Please create a project or create a collection and upload a data.']}
-                         contextMenuColumn={true}/>
+                     {this.hasAnyItems()
+                         ? <DataExplorer
+                             id={PROJECT_PANEL_ID}
+                             onRowClick={this.handleRowClick}
+                             onRowDoubleClick={this.handleRowDoubleClick}
+                             onContextMenu={this.handleContextMenu}
+                             contextMenuColumn={true}
+                             dataTableDefaultView={<DataTableDefaultView icon={ProjectIcon}/>} />
+                         : <PanelDefaultView
+                             icon={ProjectIcon}
+                             messages={['Your project is empty.', 'Please create a project or create a collection and upload a data.']} />
+                     }
                  </div>;
              }
  
+             hasAnyItems = () => {
+                 const resources = filterResources(this.isCurrentItemChild)(this.props.resources);
+                 return resources.length > 0;
+             }
+             isCurrentItemChild = (resource: Resource) => {
+                 return resource.ownerUuid === this.props.currentItemId;
+             }
              handleNewProjectClick = () => {
                  this.props.dispatch<any>(openProjectCreateDialog(this.props.currentItemId));
              }
index 7237ffc329a5cfb14faa4ce7e1d785d721679a97,a3664542eba60dde0742a58e7ed53b24e7dda5ff..23927aed2997870a53ba3faccd030359112b25b1
@@@ -28,9 -28,11 +28,11 @@@ import 
  } from "~/views-components/data-explorer/renderers";
  import { navigateTo } from "~/store/navigation/navigation-action";
  import { loadDetailsPanel } from "~/store/details-panel/details-panel-action";
- import { toggleCollectionTrashed, toggleProjectTrashed, toggleTrashed } from "~/store/trash/trash-actions";
+ import { toggleTrashed } from "~/store/trash/trash-actions";
  import { ContextMenuKind } from "~/views-components/context-menu/context-menu";
  import { Dispatch } from "redux";
+ import { PanelDefaultView } from '~/components/panel-default-view/panel-default-view';
+ import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
  
  type CssRules = "toolbar" | "button";
  
@@@ -71,7 -73,7 +73,7 @@@ export const ResourceRestore 
                  ));
              }
          }}>
-             <RestoreFromTrashIcon/>
+             <RestoreFromTrashIcon />
          </IconButton>
      );
  
@@@ -82,7 -84,8 +84,7 @@@ export const trashPanelColumns: DataCol
          configurable: true,
          sortDirection: SortDirection.ASC,
          filters: [],
 -        render: uuid => <ResourceName uuid={uuid} />,
 -        width: "450px"
 +        render: uuid => <ResourceName uuid={uuid}/>
      },
      {
          name: TrashPanelColumnNames.TYPE,
                  type: ResourceKind.PROJECT
              }
          ],
 -        render: uuid => <ResourceType uuid={uuid} />,
 -        width: "125px"
 +        render: uuid => <ResourceType uuid={uuid}/>,
      },
      {
          name: TrashPanelColumnNames.FILE_SIZE,
          configurable: true,
          sortDirection: SortDirection.NONE,
          filters: [],
 -        render: uuid => <ResourceFileSize uuid={uuid} />,
 -        width: "50px"
 +        render: uuid => <ResourceFileSize uuid={uuid} />
      },
      {
          name: TrashPanelColumnNames.TRASHED_DATE,
          configurable: true,
          sortDirection: SortDirection.NONE,
          filters: [],
 -        render: uuid => <ResourceTrashDate uuid={uuid} />,
 -        width: "50px"
 +        render: uuid => <ResourceTrashDate uuid={uuid} />
      },
      {
          name: TrashPanelColumnNames.TO_BE_DELETED,
          configurable: true,
          sortDirection: SortDirection.NONE,
          filters: [],
 -        render: uuid => <ResourceDeleteDate uuid={uuid} />,
 -        width: "50px"
 +        render: uuid => <ResourceDeleteDate uuid={uuid} />
      },
      {
          name: '',
          configurable: false,
          sortDirection: SortDirection.NONE,
          filters: [],
 -        render: uuid => <ResourceRestore uuid={uuid} />,
 -        width: "50px"
 +        render: uuid => <ResourceRestore uuid={uuid}/>
      }
  ];
  
@@@ -156,15 -164,23 +158,23 @@@ export const TrashPanel = withStyles(st
      }))(
          class extends React.Component<TrashPanelProps> {
              render() {
-                 return <DataExplorer
-                     id={TRASH_PANEL_ID}
-                     onRowClick={this.handleRowClick}
-                     onRowDoubleClick={this.handleRowDoubleClick}
-                     onContextMenu={this.handleContextMenu}
-                     defaultIcon={TrashIcon}
-                     defaultMessages={['Your trash list is empty.']}
-                     contextMenuColumn={false}/>
-                 ;
+                 return this.hasAnyTrashedResources()
+                     ? <DataExplorer
+                         id={TRASH_PANEL_ID}
+                         onRowClick={this.handleRowClick}
+                         onRowDoubleClick={this.handleRowDoubleClick}
+                         onContextMenu={this.handleContextMenu}
+                         contextMenuColumn={false}
+                         dataTableDefaultView={<DataTableDefaultView icon={TrashIcon}/>} />
+                     : <PanelDefaultView
+                         icon={TrashIcon}
+                         messages={['Your trash list is empty.']} />;
+             }
+             hasAnyTrashedResources = () => {
+                 // TODO: implement check if there is anything in the trash,
+                 //       without taking pagination into the account
+                 return true;
              }
  
              handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {