1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import * as React from 'react';
6 import TextField from '@material-ui/core/TextField';
7 import Dialog from '@material-ui/core/Dialog';
8 import DialogActions from '@material-ui/core/DialogActions';
9 import DialogContent from '@material-ui/core/DialogContent';
10 import DialogTitle from '@material-ui/core/DialogTitle';
11 import { ProjectPanelItem } from './project-panel-item';
12 import { Grid, Typography, Button, Toolbar, StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
13 import { formatDate, formatFileSize } from '../../common/formatters';
14 import DataExplorer from "../../views-components/data-explorer/data-explorer";
15 import { DataColumn, toggleSortDirection } from '../../components/data-table/data-column';
16 import { DataTableFilterItem } from '../../components/data-table-filters/data-table-filters';
17 import { ContextMenuAction } from '../../components/context-menu/context-menu';
18 import { DispatchProp, connect } from 'react-redux';
19 import actions from "../../store/data-explorer/data-explorer-action";
20 import { DataColumns } from '../../components/data-table/data-table';
21 import { ResourceKind } from "../../models/resource";
22 import { RouteComponentProps } from 'react-router';
23 import { RootState } from '../../store/store';
25 export const PROJECT_PANEL_ID = "projectPanel";
27 type ProjectPanelProps = {
28 currentItemId: string,
29 onItemClick: (item: ProjectPanelItem) => void,
30 onItemRouteChange: (itemId: string) => void
33 & WithStyles<CssRules>
34 & RouteComponentProps<{ id: string }>;
35 class ProjectPanel extends React.Component<ProjectPanelProps> {
40 handleClickOpen = () => {
41 this.setState({ open: true });
45 this.setState({ open: false });
50 <div className={this.props.classes.toolbar}>
51 <Button color="primary" variant="raised" className={this.props.classes.button}>
54 <Button color="primary" variant="raised" className={this.props.classes.button}>
57 <Button color="primary" onClick={this.handleClickOpen} variant="raised" className={this.props.classes.button}>
61 open={this.state.open}
62 onClose={this.handleClose}>
63 <div className={this.props.classes.dialog}>
64 <DialogTitle id="form-dialog-title">Create a project</DialogTitle>
65 <DialogContent className={this.props.classes.dialogContent}>
68 className={this.props.classes.textField}
75 label="Description - optional"
79 <Button onClick={this.handleClose} className={this.props.classes.button} color="primary">CANCEL</Button>
80 <Button onClick={this.handleClose} className={this.props.classes.lastButton} color="primary" variant="raised">CREATE A PROJECT</Button>
87 contextActions={contextMenuActions}
88 onColumnToggle={this.toggleColumn}
89 onFiltersChange={this.changeFilters}
90 onRowClick={this.props.onItemClick}
91 onSortToggle={this.toggleSort}
92 onSearch={this.search}
93 onContextAction={this.executeAction}
94 onChangePage={this.changePage}
95 onChangeRowsPerPage={this.changeRowsPerPage} />;
100 this.props.dispatch(actions.SET_COLUMNS({ id: PROJECT_PANEL_ID, columns }));
103 componentWillReceiveProps({ match, currentItemId }: ProjectPanelProps) {
104 if (match.params.id !== currentItemId) {
105 this.props.onItemRouteChange(match.params.id);
109 toggleColumn = (toggledColumn: DataColumn<ProjectPanelItem>) => {
110 this.props.dispatch(actions.TOGGLE_COLUMN({ id: PROJECT_PANEL_ID, columnName: toggledColumn.name }));
113 toggleSort = (column: DataColumn<ProjectPanelItem>) => {
114 this.props.dispatch(actions.TOGGLE_SORT({ id: PROJECT_PANEL_ID, columnName: column.name }));
117 changeFilters = (filters: DataTableFilterItem[], column: DataColumn<ProjectPanelItem>) => {
118 this.props.dispatch(actions.SET_FILTERS({ id: PROJECT_PANEL_ID, columnName: column.name, filters }));
121 executeAction = (action: ContextMenuAction, item: ProjectPanelItem) => {
122 alert(`Executing ${action.name} on ${item.name}`);
125 search = (searchValue: string) => {
126 this.props.dispatch(actions.SET_SEARCH_VALUE({ id: PROJECT_PANEL_ID, searchValue }));
129 changePage = (page: number) => {
130 this.props.dispatch(actions.SET_PAGE({ id: PROJECT_PANEL_ID, page }));
133 changeRowsPerPage = (rowsPerPage: number) => {
134 this.props.dispatch(actions.SET_ROWS_PER_PAGE({ id: PROJECT_PANEL_ID, rowsPerPage }));
139 type CssRules = "toolbar" | "button" | "lastButton" | "dialogContent" | "textField" | "dialog";
141 const styles: StyleRulesCallback<CssRules> = theme => ({
143 paddingBottom: theme.spacing.unit * 3,
147 marginLeft: theme.spacing.unit
150 marginLeft: theme.spacing.unit,
157 marginBottom: "32px",
165 const renderName = (item: ProjectPanelItem) =>
175 <Typography color="primary">
182 const renderIcon = (item: ProjectPanelItem) => {
184 case ResourceKind.PROJECT:
185 return <i className="fas fa-folder fa-lg" />;
186 case ResourceKind.COLLECTION:
187 return <i className="fas fa-th fa-lg" />;
193 const renderDate = (date: string) =>
198 const renderFileSize = (fileSize?: number) =>
200 {formatFileSize(fileSize)}
203 const renderOwner = (owner: string) =>
204 <Typography noWrap color="primary">
208 const renderType = (type: string) =>
213 const renderStatus = (item: ProjectPanelItem) =>
214 <Typography noWrap align="center">
218 const columns: DataColumns<ProjectPanelItem> = [{
221 sortDirection: "desc",
227 render: renderStatus,
239 render: item => renderType(item.kind),
244 render: item => renderOwner(item.owner),
249 render: item => renderFileSize(item.fileSize),
252 name: "Last modified",
254 sortDirection: "none",
255 render: item => renderDate(item.lastModified),
259 const contextMenuActions = [[{
260 icon: "fas fa-users fa-fw",
263 icon: "fas fa-sign-out-alt fa-fw",
266 icon: "fas fa-star fa-fw",
267 name: "Add to favourite"
269 icon: "fas fa-edit fa-fw",
272 icon: "fas fa-copy fa-fw",
275 icon: "fas fa-download fa-fw",
278 icon: "fas fa-trash-alt fa-fw",
283 export default withStyles(styles)(
284 connect((state: RootState) => ({ currentItemId: state.projects.currentItemId }))(