Create ProjectItem interface, update project explorer columns
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Thu, 14 Jun 2018 12:23:08 +0000 (14:23 +0200)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Thu, 14 Jun 2018 12:23:08 +0000 (14:23 +0200)
Feature #13601

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

src/components/project-explorer/project-explorer.tsx
src/views/project-explorer/project-explorer.tsx

index 490e46fd81c03eaa06147ec602095e348c0a347d..a7648433d58047d543f6ce4a2e20f6eae15923d7 100644 (file)
 
 import * as React from 'react';
 import DataExplorer, { DataExplorerProps } from "../../components/data-explorer/data-explorer";
-import { RouteComponentProps } from 'react-router';
-import { Project } from '../../models/project';
-import { ProjectState, findTreeItem } from '../../store/project/project-reducer';
-import { RootState } from '../../store/store';
-import { connect, DispatchProp } from 'react-redux';
-import { push } from 'react-router-redux';
-import projectActions from "../../store/project/project-action";
-import { Typography } from '@material-ui/core';
+import { Typography, Grid, ListItem, Divider, List } from '@material-ui/core';
 import { Column } from '../../components/data-explorer/column';
+import IconButton, { IconButtonProps } from '@material-ui/core/IconButton';
+import MoreVertIcon from "@material-ui/icons/MoreVert";
+import Popover from '../popover/popover';
+
+export interface ProjectItem {
+    name: string;
+    type: string;
+    owner: string;
+    lastModified: string;
+    fileSize?: number;
+    status?: string;
+}
 
 interface ProjectExplorerProps {
-    projects: Project[];
-    onProjectClick: (project: Project) => void;
+    items: ProjectItem[];
+    onItemClick: (item: ProjectItem) => void;
 }
 
-type ProjectExplorerState = Pick<DataExplorerProps<Project>, "columns">;
+type ProjectExplorerState = Pick<DataExplorerProps<ProjectItem>, "columns">;
 
 class ProjectExplorer extends React.Component<ProjectExplorerProps, ProjectExplorerState> {
 
     state: ProjectExplorerState = {
         columns: [
-            { header: "Name", selected: true, render: item => <Typography noWrap>{renderIcon(item.kind)} {item.name}</Typography> },
-            { header: "Created at", selected: true, render: item => <Typography noWrap>{formatDate(item.createdAt)}</Typography> },
-            { header: "Modified at", selected: true, render: item => <Typography noWrap>{formatDate(item.modifiedAt)}</Typography> },
-            { header: "UUID", selected: true, render: item => <Typography noWrap>{item.uuid}</Typography> },
-            { header: "Owner UUID", selected: true, render: item => <Typography noWrap>{item.ownerUuid}</Typography> },
-            { header: "URL", selected: true, render: item => <Typography noWrap>{item.href}</Typography> }
+            {
+                header: "Name",
+                selected: true,
+                render: item => (
+                    <Grid container onClick={() => this.props.onItemClick(item)}>
+                        {renderIcon(item)}
+                        <Typography style={{ marginLeft: 8 }}>
+                            {item.name}
+                        </Typography>
+                    </Grid>
+                )
+            },
+            {
+                header: "Status",
+                selected: true,
+                render: item => (
+                    <Typography noWrap align="center">
+                        {item.status || "-"}
+                    </Typography>
+                )
+            },
+            {
+                header: "Type",
+                selected: true,
+                render: item => (
+                    <Typography noWrap>
+                        {item.type}
+                    </Typography>
+                )
+            },
+            {
+                header: "Owner",
+                selected: true,
+                render: item => (
+                    <Typography noWrap>
+                        {item.owner}
+                    </Typography>
+                )
+            },
+            {
+                header: "File size",
+                selected: true,
+                render: ({ fileSize }) => (
+                    <Typography noWrap>
+                        {typeof fileSize === "number" ? formatFileSize(fileSize) : "-"}
+                    </Typography>
+                )
+            },
+            {
+                header: "Last modified",
+                selected: true,
+                render: item => (
+                    <Typography noWrap>
+                        {formatDate(item.lastModified)}
+                    </Typography>
+                )
+            },
+            {
+                header: "Actions",
+                selected: true,
+                render: item => (
+                    <Popover triggerComponent={ItemActionsTrigger}>
+                        <List>
+                            <ListItem>Share</ListItem>
+                            <Divider />
+                            <ListItem>Remove</ListItem>
+                        </List>
+                    </Popover>
+                )
+            }
         ]
     };
 
@@ -38,14 +107,13 @@ class ProjectExplorer extends React.Component<ProjectExplorerProps, ProjectExplo
         return (
             <DataExplorer
                 columns={this.state.columns}
-                items={this.props.projects}
-                onItemClick={this.props.onProjectClick}
+                items={this.props.items}
                 onColumnToggle={this.toggleColumn}
             />
         );
     }
 
-    toggleColumn = (column: Column<Project>) => {
+    toggleColumn = (column: Column<ProjectItem>) => {
         const index = this.state.columns.indexOf(column);
         const columns = this.state.columns.slice(0);
         columns.splice(index, 1, { ...column, selected: !column.selected });
@@ -58,8 +126,23 @@ const formatDate = (isoDate: string) => {
     return date.toLocaleString();
 };
 
-const renderIcon = (kind: string) => {
-    switch (kind) {
+const formatFileSize = (size: number) => {
+    switch (true) {
+        case size > 1000000000000:
+            return `${size / 1000000000000} TB`;
+        case size > 1000000000:
+            return `${size / 1000000000} GB`;
+        case size > 1000000:
+            return `${size / 1000000} MB`;
+        case size > 1000:
+            return `${size / 1000} KB`;
+        default:
+            return `${size} B`;
+    }
+};
+
+const renderIcon = (projectItem: ProjectItem) => {
+    switch (projectItem.type) {
         case "arvados#group":
             return <i className="fas fa-folder" />;
         case "arvados#groupList":
@@ -69,4 +152,10 @@ const renderIcon = (kind: string) => {
     }
 };
 
+const ItemActionsTrigger: React.SFC<IconButtonProps> = (props) => (
+    <IconButton {...props}>
+        <MoreVertIcon />
+    </IconButton>
+);
+
 export default ProjectExplorer;
index de91c0bf37d076b400002efcc1f0ecb340c11f33..ec08b02384f8238ee5a97c26aabd37d65c3fb34a 100644 (file)
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from 'react';
-import DataExplorer, { DataExplorerProps } from "../../components/data-explorer/data-explorer";
+import { DataExplorerProps } from "../../components/data-explorer/data-explorer";
 import { RouteComponentProps } from 'react-router';
 import { Project } from '../../models/project';
 import { ProjectState, findTreeItem } from '../../store/project/project-reducer';
@@ -11,9 +11,8 @@ import { RootState } from '../../store/store';
 import { connect, DispatchProp } from 'react-redux';
 import { push } from 'react-router-redux';
 import projectActions from "../../store/project/project-action";
-import { Typography } from '@material-ui/core';
-import { Column } from '../../components/data-explorer/column';
-import ProjectExplorer from '../../components/project-explorer/project-explorer';
+import ProjectExplorer, { ProjectItem } from '../../components/project-explorer/project-explorer';
+import { TreeItem } from '../../components/tree/tree';
 
 interface ProjectExplorerViewDataProps {
     projects: ProjectState;
@@ -23,6 +22,10 @@ type ProjectExplorerViewProps = ProjectExplorerViewDataProps & RouteComponentPro
 
 type ProjectExplorerViewState = Pick<DataExplorerProps<Project>, "columns">;
 
+interface MappedProjectItem extends ProjectItem {
+    uuid: string;
+}
+
 class ProjectExplorerView extends React.Component<ProjectExplorerViewProps, ProjectExplorerViewState> {
 
     render() {
@@ -30,19 +33,28 @@ class ProjectExplorerView extends React.Component<ProjectExplorerViewProps, Proj
         const projectItems = project && project.items || [];
         return (
             <ProjectExplorer
-                projects={projectItems.map(item => item.data)}
-                onProjectClick={this.goToProject}
+                items={projectItems.map(mapTreeItem)}
+                onItemClick={this.goToProject}
             />
         );
     }
 
-    goToProject = (project: Project) => {
+    goToProject = (project: MappedProjectItem) => {
         this.props.dispatch(push(`/project/${project.uuid}`));
         this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(project.uuid));
     }
 
 }
 
+const mapTreeItem = (item: TreeItem<Project>): MappedProjectItem => ({
+    name: item.data.name,
+    type: item.data.kind,
+    owner: item.data.ownerUuid,
+    lastModified: item.data.modifiedAt,
+    uuid: item.data.uuid
+});
+
+
 export default connect(
     (state: RootState) => ({
         projects: state.projects