const store = configureStore({
projects: [
],
+ collections: [
+ ],
router: {
location: null
},
href: string;
kind: string;
}
+
+export enum ResourceKind {
+ PROJECT = "project",
+ COLLECTION = "collection",
+ PIPELINE = "pipeline",
+ LEVEL_UP = "levelup",
+ UNKNOWN = "unknown"
+}
+
+export function getResourceKind(itemKind: string) {
+ switch (itemKind) {
+ case "arvados#project": return ResourceKind.PROJECT;
+ case "arvados#collection": return ResourceKind.COLLECTION;
+ case "arvados#pipeline": return ResourceKind.PIPELINE;
+ default:
+ return ResourceKind.UNKNOWN;
+ }
+}
return item;
}
+export function getActiveTreeItem<T>(tree: Array<TreeItem<T>>): TreeItem<T> | undefined {
+ let item;
+ for (const t of tree) {
+ item = t.active
+ ? t
+ : getActiveTreeItem(t.items ? t.items : []);
+ if (item) {
+ break;
+ }
+ }
+ return item;
+}
+
export function getTreePath<T>(tree: Array<TreeItem<T>>, itemId: string): Array<TreeItem<T>> {
- for(const item of tree){
+ for (const item of tree){
if(item.id === itemId){
return [item];
} else {
import { History } from "history";
import projectsReducer, { ProjectState } from "./project/project-reducer";
import authReducer, { AuthState } from "./auth/auth-reducer";
-import collectionsReducer from "./collection/collection-reducer";
+import collectionsReducer, { CollectionState } from "./collection/collection-reducer";
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
export interface RootState {
auth: AuthState;
projects: ProjectState;
+ collections: CollectionState;
router: RouterState;
}
// SPDX-License-Identifier: AGPL-3.0
import * as React from 'react';
-import { Typography, Grid, Paper, Toolbar } from '@material-ui/core';
+import { Grid, Paper, Toolbar, Typography } from '@material-ui/core';
import IconButton from '@material-ui/core/IconButton';
import MoreVertIcon from "@material-ui/icons/MoreVert";
-import { formatFileSize, formatDate } from '../../common/formatters';
+import { formatDate, formatFileSize } from '../../common/formatters';
import { DataItem } from './data-item';
-import { DataColumns } from "../../components/data-table/data-table";
+import DataTable, { DataColumns } from "../../components/data-table/data-table";
import ContextMenu from "../../components/context-menu/context-menu";
import ColumnSelector from "../../components/column-selector/column-selector";
-import DataTable from "../../components/data-table/data-table";
import { mockAnchorFromMouseEvent } from "../../components/popover/helpers";
import { DataColumn } from "../../components/data-table/data-column";
+import { ResourceKind } from "../../models/resource";
export interface DataExplorerContextActions {
onAddToFavourite: (dataIitem: DataItem) => void;
const renderIcon = (dataItem: DataItem) => {
switch (dataItem.type) {
- case "arvados#group":
- return <i className="fas fa-folder fa-lg" />;
- case "arvados#groupList":
- return <i className="fas fa-th fa-lg" />;
+ case ResourceKind.LEVEL_UP:
+ return <i className="icon-level-up" style={{fontSize: "1rem"}}/>;
+ case ResourceKind.PROJECT:
+ return <i className="fas fa-folder fa-lg"/>;
+ case ResourceKind.COLLECTION:
+ return <i className="fas fa-th fa-lg"/>;
default:
return <i />;
}
//
// SPDX-License-Identifier: AGPL-3.0
+import { getResourceKind, Resource, ResourceKind } from "../../models/resource";
+
export interface DataItem {
uuid: string;
name: string;
- type: string;
+ type: ResourceKind;
+ url: string;
owner: string;
lastModified: string;
fileSize?: number;
status?: string;
}
+
+function resourceToDataItem(r: Resource, kind?: ResourceKind) {
+ return {
+ uuid: r.uuid,
+ name: r.name,
+ type: kind ? kind : getResourceKind(r.kind),
+ owner: r.ownerUuid,
+ lastModified: r.modifiedAt
+ };
+}
+
import { TreeItem } from "../../components/tree/tree";
import { Project } from "../../models/project";
import { DataItem } from "../../views-components/data-explorer/data-item";
+import { findTreeItem } from "../../store/project/project-reducer";
+import { ResourceKind } from "../../models/resource";
+import { Collection } from "../../models/collection";
+
+
+export const projectExplorerItems = (projects: Array<TreeItem<Project>>, treeItemId: string, collections: Array<Collection>): DataItem[] => {
+ const dataItems: DataItem[] = [];
+
+ const treeItem = findTreeItem(projects, treeItemId);
+ if (treeItem) {
+ dataItems.push({
+ name: "..",
+ url: `/projects/${treeItem.data.ownerUuid}`,
+ type: ResourceKind.LEVEL_UP,
+ owner: treeItem.data.ownerUuid,
+ uuid: treeItem.data.uuid,
+ lastModified: treeItem.data.modifiedAt
+ });
+
+ if (treeItem.items) {
+ treeItem.items.forEach(p => {
+ const item = {
+ name: p.data.name,
+ type: ResourceKind.PROJECT,
+ url: `/projects/${treeItem.data.uuid}`,
+ owner: p.data.ownerUuid,
+ uuid: p.data.uuid,
+ lastModified: p.data.modifiedAt
+ } as DataItem;
+
+ dataItems.push(item);
+ });
+ }
+ }
+
+ collections.forEach(c => {
+ const item = {
+ name: c.name,
+ type: ResourceKind.COLLECTION,
+ url: `/collections/${c.uuid}`,
+ owner: c.ownerUuid,
+ uuid: c.uuid,
+ lastModified: c.modifiedAt
+ } as DataItem;
+
+ dataItems.push(item);
+ });
+
+ return dataItems;
+};
-export const mapProjectTreeItem = (item: TreeItem<Project>): DataItem => ({
- name: item.data.name,
- type: item.data.kind,
- owner: item.data.ownerUuid,
- lastModified: item.data.modifiedAt,
- uuid: item.data.uuid
-});
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Project } from '../../models/project';
-import { ProjectState, findTreeItem } from '../../store/project/project-reducer';
+import { ProjectState } 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 { DataColumns } from "../../components/data-table/data-table";
import DataExplorer, { DataExplorerContextActions } from "../../views-components/data-explorer/data-explorer";
-import { mapProjectTreeItem } from "./data-explorer-selectors";
+import { projectExplorerItems } from "./data-explorer-selectors";
import { DataItem } from "../../views-components/data-explorer/data-item";
+import { CollectionState } from "../../store/collection/collection-reducer";
+import { ResourceKind } from "../../models/resource";
+import projectActions from "../../store/project/project-action";
+import { getCollectionList } from "../../store/collection/collection-action";
interface DataExplorerViewDataProps {
projects: ProjectState;
+ collections: CollectionState;
}
-type DataExplorerViewProps = DataExplorerViewDataProps & RouteComponentProps<{ name: string }> & DispatchProp;
+type DataExplorerViewProps = DataExplorerViewDataProps & RouteComponentProps<{ uuid: string }> & DispatchProp;
type DataExplorerViewState = DataColumns<Project>;
class DataExplorerView extends React.Component<DataExplorerViewProps, DataExplorerViewState> {
-
render() {
- const project = findTreeItem(this.props.projects, this.props.match.params.name);
- const projectItems = project && project.items || [];
+ const treeItemId = this.props.match.params.uuid;
+ const items = projectExplorerItems(this.props.projects, treeItemId, this.props.collections);
return (
<DataExplorer
- items={projectItems.map(mapProjectTreeItem)}
- onItemClick={this.goToProject}
+ items={items}
+ onItemClick={this.goToItem}
contextActions={this.contextActions}
/>
);
onShare: console.log
};
- goToProject = (item: DataItem) => {
- this.props.dispatch(push(`/project/${item}`));
- this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(item.uuid));
+ goToItem = (item: DataItem) => {
+ // FIXME: Unify project tree switch action
+ this.props.dispatch(push(item.url));
+ if (item.type === ResourceKind.PROJECT || item.type === ResourceKind.LEVEL_UP) {
+ this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(item.uuid));
+ }
+ this.props.dispatch<any>(getCollectionList(item.uuid));
}
}
export default connect(
(state: RootState) => ({
- projects: state.projects
+ projects: state.projects,
+ collections: state.collections
})
)(DataExplorerView);
import { Project } from "../../models/project";
import { getTreePath } from '../../store/project/project-reducer';
import DataExplorer from '../data-explorer/data-explorer';
+import { getCollectionList } from "../../store/collection/collection-action";
const drawerWidth = 240;
const appBarHeight = 102;
}
};
-
mainAppBarActions: MainAppBarActionProps = {
onBreadcrumbClick: ({ itemId, status }: NavBreadcrumb) => {
this.toggleProjectTreeItem(itemId, status);
this.props.dispatch<any>(getProjectList(itemId))
.then(() => this.openProjectItem(itemId));
}
+ this.props.dispatch<any>(getCollectionList(itemId));
}
openProjectItem = (itemId: string) => {
<main className={classes.contentWrapper}>
<div className={classes.content}>
<Switch>
- <Route path="/project/:name" component={DataExplorer} />
+ <Route path="/project/:uuid" component={DataExplorer} />
</Switch>
</div>
</main>
"no-debugger": false,
"no-console": false,
"no-shadowed-variable": false,
- "semicolon": true
+ "semicolon": true,
+ "array-type": false
},
"linterOptions": {
"exclude": [