1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import * as React from 'react';
6 import { ProjectPanelItem } from './project-panel-item';
7 import { Grid, Typography, Button, Toolbar, StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
8 import { formatDate, formatFileSize } from '../../common/formatters';
9 import DataExplorer from "../../views-components/data-explorer/data-explorer";
10 import { ContextMenuAction } from '../../components/context-menu/context-menu';
11 import { DispatchProp, connect } from 'react-redux';
12 import { DataColumns } from '../../components/data-table/data-table';
13 import { RouteComponentProps } from 'react-router';
14 import { RootState } from '../../store/store';
15 import { ResourceKind } from '../../models/kinds';
16 import { DataTableFilterItem } from '../../components/data-table-filters/data-table-filters';
17 import { ContainerRequestState } from '../../models/container-request';
18 import { SortDirection } from '../../components/data-table/data-column';
19 import DialogProjectCreate from '../../components/dialog-create/dialog-project-create';
20 import { mockAnchorFromMouseEvent } from "../../components/popover/helpers";
22 export const PROJECT_PANEL_ID = "projectPanel";
24 export interface ProjectPanelFilter extends DataTableFilterItem {
25 type: ResourceKind | ContainerRequestState;
28 interface DataExplorerState<T> {
30 anchorEl?: HTMLElement;
36 type ProjectPanelProps = {
37 currentItemId: string,
38 onItemClick: (item: ProjectPanelItem) => void,
39 onItemRouteChange: (itemId: string) => void,
40 onContextMenu: (event: React.MouseEvent<HTMLElement>, item: ProjectPanelItem) => void;
41 handleCreationDialogOpen: () => void;
42 handleCreationDialogClose: () => void;
43 isCreationDialogOpen: boolean;
46 & WithStyles<CssRules>
47 & RouteComponentProps<{ id: string }>;
49 class ProjectPanel extends React.Component<ProjectPanelProps, DataExplorerState<any>> {
50 state: DataExplorerState<any> = {
57 <div className={this.props.classes.toolbar}>
58 <Button color="primary" variant="raised" className={this.props.classes.button}>
61 <Button color="primary" variant="raised" className={this.props.classes.button}>
64 <Button color="primary" onClick={this.props.handleCreationDialogOpen} variant="raised" className={this.props.classes.button}>
67 <DialogProjectCreate open={this.props.isCreationDialogOpen} handleClose={this.props.handleCreationDialogClose}/>
71 onRowClick={this.props.onItemClick}
72 onContextMenu={this.props.onContextMenu} />;
76 componentWillReceiveProps({ match, currentItemId }: ProjectPanelProps) {
77 if (match.params.id !== currentItemId) {
78 this.props.onItemRouteChange(match.params.id);
82 executeAction = (action: ContextMenuAction, item: ProjectPanelItem) => {
83 alert(`Executing ${action.name} on ${item.name}`);
86 openContextMenu = (event: React.MouseEvent<HTMLElement>, item: any) => {
87 event.preventDefault();
88 event.stopPropagation();
91 anchorEl: mockAnchorFromMouseEvent(event),
97 closeContextMenu = () => {
98 this.setState({ contextMenu: {} });
103 type CssRules = "toolbar" | "button";
105 const styles: StyleRulesCallback<CssRules> = theme => ({
107 paddingBottom: theme.spacing.unit * 3,
111 marginLeft: theme.spacing.unit
115 const renderName = (item: ProjectPanelItem) =>
125 <Typography color="primary">
132 const renderIcon = (item: ProjectPanelItem) => {
134 case ResourceKind.Project:
135 return <i className="fas fa-folder fa-lg" />;
136 case ResourceKind.Collection:
137 return <i className="fas fa-archive fa-lg" />;
138 case ResourceKind.Process:
139 return <i className="fas fa-cogs fa-lg" />;
145 const renderDate = (date: string) =>
150 const renderFileSize = (fileSize?: number) =>
152 {formatFileSize(fileSize)}
155 const renderOwner = (owner: string) =>
156 <Typography noWrap color="primary">
162 const typeToLabel = (type: string) => {
164 case ResourceKind.Collection:
165 return "Data collection";
166 case ResourceKind.Project:
168 case ResourceKind.Process:
175 const renderType = (type: string) => {
176 return <Typography noWrap>
181 const renderStatus = (item: ProjectPanelItem) =>
182 <Typography noWrap align="center">
186 export enum ProjectPanelColumnNames {
191 FileSize = "File size",
192 LastModified = "Last modified"
196 export const columns: DataColumns<ProjectPanelItem, ProjectPanelFilter> = [{
197 name: ProjectPanelColumnNames.Name,
199 sortDirection: SortDirection.Asc,
206 name: ContainerRequestState.Committed,
208 type: ContainerRequestState.Committed
210 name: ContainerRequestState.Final,
212 type: ContainerRequestState.Final
214 name: ContainerRequestState.Uncommitted,
216 type: ContainerRequestState.Uncommitted
218 render: renderStatus,
221 name: ProjectPanelColumnNames.Type,
224 name: typeToLabel(ResourceKind.Collection),
226 type: ResourceKind.Collection
228 name: typeToLabel(ResourceKind.Process),
230 type: ResourceKind.Process
232 name: typeToLabel(ResourceKind.Project),
234 type: ResourceKind.Project
236 render: item => renderType(item.kind),
239 name: ProjectPanelColumnNames.Owner,
241 render: item => renderOwner(item.owner),
244 name: ProjectPanelColumnNames.FileSize,
246 render: item => renderFileSize(item.fileSize),
249 name: ProjectPanelColumnNames.LastModified,
251 sortDirection: SortDirection.None,
252 render: item => renderDate(item.lastModified),
257 export default withStyles(styles)(
258 connect((state: RootState) => ({ currentItemId: state.projects.currentItemId }))(