46d5fb50f3783c89c9852892716891c6d260732c
[arvados-workbench2.git] / src / components / data-explorer / data-explorer.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import { Grid, Paper, Toolbar, StyleRulesCallback, withStyles, WithStyles, TablePagination, IconButton } from '@material-ui/core';
7 import MoreVertIcon from "@material-ui/icons/MoreVert";
8 import { ColumnSelector } from "../column-selector/column-selector";
9 import { DataTable, DataColumns } from "../data-table/data-table";
10 import { DataColumn } from "../data-table/data-column";
11 import { DataTableFilterItem } from '../data-table-filters/data-table-filters';
12 import { SearchInput } from '../search-input/search-input';
13 import { ArvadosTheme } from "../../common/custom-theme";
14
15 type CssRules = "searchBox" | "toolbar";
16
17 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
18     searchBox: {
19         paddingBottom: theme.spacing.unit * 2
20     },
21     toolbar: {
22         paddingTop: theme.spacing.unit * 2
23     }
24 });
25
26 interface DataExplorerDataProps<T> {
27     items: T[];
28     itemsAvailable: number;
29     columns: DataColumns<T>;
30     searchValue: string;
31     rowsPerPage: number;
32     rowsPerPageOptions: number[];
33     page: number;
34     onSearch: (value: string) => void;
35     onRowClick: (item: T) => void;
36     onRowDoubleClick: (item: T) => void;
37     onColumnToggle: (column: DataColumn<T>) => void;
38     onContextMenu: (event: React.MouseEvent<HTMLElement>, item: T) => void;
39     onSortToggle: (column: DataColumn<T>) => void;
40     onFiltersChange: (filters: DataTableFilterItem[], column: DataColumn<T>) => void;
41     onChangePage: (page: number) => void;
42     onChangeRowsPerPage: (rowsPerPage: number) => void;
43     extractKey?: (item: T) => React.Key;
44 }
45
46 type DataExplorerProps<T> = DataExplorerDataProps<T> & WithStyles<CssRules>;
47
48 export const DataExplorer = withStyles(styles)(
49     class DataExplorerGeneric<T> extends React.Component<DataExplorerProps<T>> {
50         render() {
51             return <Paper>
52                 <Toolbar className={this.props.classes.toolbar}>
53                     <Grid container justify="space-between" wrap="nowrap" alignItems="center">
54                         <div className={this.props.classes.searchBox}>
55                             <SearchInput
56                                 value={this.props.searchValue}
57                                 onSearch={this.props.onSearch}/>
58                         </div>
59                         <ColumnSelector
60                             columns={this.props.columns}
61                             onColumnToggle={this.props.onColumnToggle}/>
62                     </Grid>
63                 </Toolbar>
64                 <DataTable
65                     columns={[...this.props.columns, this.contextMenuColumn]}
66                     items={this.props.items}
67                     onRowClick={(_, item: T) => this.props.onRowClick(item)}
68                     onContextMenu={this.props.onContextMenu}
69                     onRowDoubleClick={(_, item: T) => this.props.onRowDoubleClick(item)}
70                     onFiltersChange={this.props.onFiltersChange}
71                     onSortToggle={this.props.onSortToggle}
72                     extractKey={this.props.extractKey}/>
73                 <Toolbar>
74                     {this.props.items.length > 0 &&
75                     <Grid container justify="flex-end">
76                         <TablePagination
77                             count={this.props.itemsAvailable}
78                             rowsPerPage={this.props.rowsPerPage}
79                             rowsPerPageOptions={this.props.rowsPerPageOptions}
80                             page={this.props.page}
81                             onChangePage={this.changePage}
82                             onChangeRowsPerPage={this.changeRowsPerPage}
83                             component="div"
84                         />
85                     </Grid>}
86                 </Toolbar>
87             </Paper>;
88         }
89
90         changePage = (event: React.MouseEvent<HTMLButtonElement>, page: number) => {
91             this.props.onChangePage(page);
92         }
93
94         changeRowsPerPage: React.ChangeEventHandler<HTMLTextAreaElement | HTMLInputElement> = (event) => {
95             this.props.onChangeRowsPerPage(parseInt(event.target.value, 10));
96         }
97
98         renderContextMenuTrigger = (item: T) =>
99             <Grid container justify="flex-end">
100                 <IconButton onClick={event => this.props.onContextMenu(event, item)}>
101                     <MoreVertIcon/>
102                 </IconButton>
103             </Grid>
104
105         contextMenuColumn = {
106             name: "Actions",
107             selected: true,
108             configurable: false,
109             key: "context-actions",
110             render: this.renderContextMenuTrigger,
111             width: "auto"
112         };
113     }
114 );