4fc9fb9c3982aeef1d45a07b0fe848a150e97d5a
[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 } from '@material-ui/core';
7 import ContextMenu, { ContextMenuActionGroup } from "../../components/context-menu/context-menu";
8 import ColumnSelector from "../../components/column-selector/column-selector";
9 import DataTable from "../../components/data-table/data-table";
10 import { mockAnchorFromMouseEvent } from "../../components/popover/helpers";
11 import { DataColumn, toggleSortDirection } from "../../components/data-table/data-column";
12 import { DataTableFilterItem } from '../../components/data-table-filters/data-table-filters';
13 import { DataExplorerColumn } from './data-explorer-column';
14
15 interface DataExplorerProps<T> {
16     items: T[];
17     columns: Array<DataExplorerColumn<T>>;
18     contextActions: Array<ContextMenuActionGroup<T>>;
19     onRowClick: (item: T) => void;
20     onColumnToggle: (column: DataExplorerColumn<T>) => void;
21     onSortingToggle: (column: DataExplorerColumn<T>) => void;
22     onFiltersChange: (columns: DataExplorerColumn<T>) => void;
23 }
24
25 interface DataExplorerState<T> {
26     contextMenu: {
27         anchorEl?: HTMLElement;
28         item?: T;
29     };
30 }
31
32 class DataExplorer<T> extends React.Component<DataExplorerProps<T>, DataExplorerState<T>> {
33     state: DataExplorerState<T> = {
34         contextMenu: {}
35     };
36
37     render() {
38         return <Paper>
39             <ContextMenu
40                 {...this.state.contextMenu}
41                 actions={this.contextActions}
42                 onClose={this.closeContextMenu} />
43             <Toolbar>
44                 <Grid container justify="flex-end">
45                     <ColumnSelector
46                         columns={this.columns}
47                         onColumnToggle={this.toggleColumn} />
48                 </Grid>
49             </Toolbar>
50             <DataTable
51                 columns={this.columns}
52                 items={this.props.items}
53                 onRowClick={(_, row: T) => this.props.onRowClick(row)}
54                 onRowContextMenu={this.openItemMenuOnRowClick} />
55             <Toolbar />
56         </Paper>;
57     }
58
59     get columns(): Array<DataColumn<T>> {
60         return this.props.columns.map((column): DataColumn<T> => ({
61             configurable: column.configurable,
62             filters: column.filters,
63             name: column.name,
64             onFiltersChange: column.filterable ? this.changeFilters(column) : undefined,
65             onSortToggle: column.sortable ? this.toggleSort(column) : undefined,
66             render: column.render,
67             renderHeader: column.renderHeader,
68             selected: column.selected,
69             sortDirection: column.sortDirection
70         }));
71     }
72
73     get contextActions() {
74         return this.props.contextActions.map(actionGroup =>
75             actionGroup.map(action => ({
76                 ...action,
77                 onClick: (item: T) => {
78                     this.closeContextMenu();
79                     action.onClick(item);
80                 }
81             })));
82     }
83
84     toggleColumn = (column: DataExplorerColumn<T>) => {
85         this.props.onColumnToggle(column);
86     }
87
88     toggleSort = (column: DataExplorerColumn<T>) => () => {
89         this.props.onSortingToggle(toggleSortDirection(column));
90     }
91
92     changeFilters = (column: DataExplorerColumn<T>) => (filters: DataTableFilterItem[]) => {
93         this.props.onFiltersChange({ ...column, filters });
94     }
95
96     openItemMenuOnRowClick = (event: React.MouseEvent<HTMLElement>, item: T) => {
97         event.preventDefault();
98         this.setState({
99             contextMenu: {
100                 anchorEl: mockAnchorFromMouseEvent(event),
101                 item
102             }
103         });
104     }
105
106     openItemMenuOnActionsClick = (event: React.MouseEvent<HTMLElement>, item: T) => {
107         this.setState({
108             contextMenu: {
109                 anchorEl: event.currentTarget,
110                 item
111             }
112         });
113     }
114
115     closeContextMenu = () => {
116         this.setState({ contextMenu: {} });
117     }
118
119 }
120
121 export default DataExplorer;