Create ProjectItem interface, update project explorer columns
[arvados.git] / src / components / project-explorer / project-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 DataExplorer, { DataExplorerProps } from "../../components/data-explorer/data-explorer";
7 import { Typography, Grid, ListItem, Divider, List } from '@material-ui/core';
8 import { Column } from '../../components/data-explorer/column';
9 import IconButton, { IconButtonProps } from '@material-ui/core/IconButton';
10 import MoreVertIcon from "@material-ui/icons/MoreVert";
11 import Popover from '../popover/popover';
12
13 export interface ProjectItem {
14     name: string;
15     type: string;
16     owner: string;
17     lastModified: string;
18     fileSize?: number;
19     status?: string;
20 }
21
22 interface ProjectExplorerProps {
23     items: ProjectItem[];
24     onItemClick: (item: ProjectItem) => void;
25 }
26
27 type ProjectExplorerState = Pick<DataExplorerProps<ProjectItem>, "columns">;
28
29 class ProjectExplorer extends React.Component<ProjectExplorerProps, ProjectExplorerState> {
30
31     state: ProjectExplorerState = {
32         columns: [
33             {
34                 header: "Name",
35                 selected: true,
36                 render: item => (
37                     <Grid container onClick={() => this.props.onItemClick(item)}>
38                         {renderIcon(item)}
39                         <Typography style={{ marginLeft: 8 }}>
40                             {item.name}
41                         </Typography>
42                     </Grid>
43                 )
44             },
45             {
46                 header: "Status",
47                 selected: true,
48                 render: item => (
49                     <Typography noWrap align="center">
50                         {item.status || "-"}
51                     </Typography>
52                 )
53             },
54             {
55                 header: "Type",
56                 selected: true,
57                 render: item => (
58                     <Typography noWrap>
59                         {item.type}
60                     </Typography>
61                 )
62             },
63             {
64                 header: "Owner",
65                 selected: true,
66                 render: item => (
67                     <Typography noWrap>
68                         {item.owner}
69                     </Typography>
70                 )
71             },
72             {
73                 header: "File size",
74                 selected: true,
75                 render: ({ fileSize }) => (
76                     <Typography noWrap>
77                         {typeof fileSize === "number" ? formatFileSize(fileSize) : "-"}
78                     </Typography>
79                 )
80             },
81             {
82                 header: "Last modified",
83                 selected: true,
84                 render: item => (
85                     <Typography noWrap>
86                         {formatDate(item.lastModified)}
87                     </Typography>
88                 )
89             },
90             {
91                 header: "Actions",
92                 selected: true,
93                 render: item => (
94                     <Popover triggerComponent={ItemActionsTrigger}>
95                         <List>
96                             <ListItem>Share</ListItem>
97                             <Divider />
98                             <ListItem>Remove</ListItem>
99                         </List>
100                     </Popover>
101                 )
102             }
103         ]
104     };
105
106     render() {
107         return (
108             <DataExplorer
109                 columns={this.state.columns}
110                 items={this.props.items}
111                 onColumnToggle={this.toggleColumn}
112             />
113         );
114     }
115
116     toggleColumn = (column: Column<ProjectItem>) => {
117         const index = this.state.columns.indexOf(column);
118         const columns = this.state.columns.slice(0);
119         columns.splice(index, 1, { ...column, selected: !column.selected });
120         this.setState({ columns });
121     }
122 }
123
124 const formatDate = (isoDate: string) => {
125     const date = new Date(isoDate);
126     return date.toLocaleString();
127 };
128
129 const formatFileSize = (size: number) => {
130     switch (true) {
131         case size > 1000000000000:
132             return `${size / 1000000000000} TB`;
133         case size > 1000000000:
134             return `${size / 1000000000} GB`;
135         case size > 1000000:
136             return `${size / 1000000} MB`;
137         case size > 1000:
138             return `${size / 1000} KB`;
139         default:
140             return `${size} B`;
141     }
142 };
143
144 const renderIcon = (projectItem: ProjectItem) => {
145     switch (projectItem.type) {
146         case "arvados#group":
147             return <i className="fas fa-folder" />;
148         case "arvados#groupList":
149             return <i className="fas fa-th" />;
150         default:
151             return <i />;
152     }
153 };
154
155 const ItemActionsTrigger: React.SFC<IconButtonProps> = (props) => (
156     <IconButton {...props}>
157         <MoreVertIcon />
158     </IconButton>
159 );
160
161 export default ProjectExplorer;