From: Daniel Kos Date: Fri, 22 Jun 2018 12:11:16 +0000 (+0200) Subject: Added data selector for workbench data explorer X-Git-Tag: 1.2.0~67^2~5 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/969254757ab4c21840faedf2bd1e4297c35203ac Added data selector for workbench data explorer Feature #13666 Arvados-DCO-1.1-Signed-off-by: Daniel Kos --- diff --git a/src/index.tsx b/src/index.tsx index cf1610f8..28f8300d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -21,6 +21,8 @@ const history = createBrowserHistory(); const store = configureStore({ projects: [ ], + collections: [ + ], router: { location: null }, diff --git a/src/models/resource.ts b/src/models/resource.ts index 39b4e915..4c198fb8 100644 --- a/src/models/resource.ts +++ b/src/models/resource.ts @@ -7,3 +7,21 @@ export interface Resource { 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; + } +} diff --git a/src/store/project/project-reducer.ts b/src/store/project/project-reducer.ts index 4f7545fc..2c74eb23 100644 --- a/src/store/project/project-reducer.ts +++ b/src/store/project/project-reducer.ts @@ -22,8 +22,21 @@ export function findTreeItem(tree: Array>, itemId: string): TreeI return item; } +export function getActiveTreeItem(tree: Array>): TreeItem | 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(tree: Array>, itemId: string): Array> { - for(const item of tree){ + for (const item of tree){ if(item.id === itemId){ return [item]; } else { diff --git a/src/store/store.ts b/src/store/store.ts index 6b9c31ff..6053e037 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -8,7 +8,7 @@ import thunkMiddleware from 'redux-thunk'; 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' && @@ -18,6 +18,7 @@ const composeEnhancers = export interface RootState { auth: AuthState; projects: ProjectState; + collections: CollectionState; router: RouterState; } diff --git a/src/views-components/data-explorer/data-explorer.tsx b/src/views-components/data-explorer/data-explorer.tsx index c4de01a3..4ba0f87c 100644 --- a/src/views-components/data-explorer/data-explorer.tsx +++ b/src/views-components/data-explorer/data-explorer.tsx @@ -3,17 +3,17 @@ // 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; @@ -191,10 +191,12 @@ class DataExplorer extends React.Component const renderIcon = (dataItem: DataItem) => { switch (dataItem.type) { - case "arvados#group": - return ; - case "arvados#groupList": - return ; + case ResourceKind.LEVEL_UP: + return ; + case ResourceKind.PROJECT: + return ; + case ResourceKind.COLLECTION: + return ; default: return ; } diff --git a/src/views-components/data-explorer/data-item.ts b/src/views-components/data-explorer/data-item.ts index 65e8f632..ebff77d8 100644 --- a/src/views-components/data-explorer/data-item.ts +++ b/src/views-components/data-explorer/data-item.ts @@ -2,12 +2,26 @@ // // 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 + }; +} + diff --git a/src/views/data-explorer/data-explorer-selectors.ts b/src/views/data-explorer/data-explorer-selectors.ts index 5f17037f..73881fad 100644 --- a/src/views/data-explorer/data-explorer-selectors.ts +++ b/src/views/data-explorer/data-explorer-selectors.ts @@ -1,11 +1,54 @@ 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>, treeItemId: string, collections: Array): 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): DataItem => ({ - name: item.data.name, - type: item.data.kind, - owner: item.data.ownerUuid, - lastModified: item.data.modifiedAt, - uuid: item.data.uuid -}); diff --git a/src/views/data-explorer/data-explorer.tsx b/src/views/data-explorer/data-explorer.tsx index f4ee36f3..a667469a 100644 --- a/src/views/data-explorer/data-explorer.tsx +++ b/src/views/data-explorer/data-explorer.tsx @@ -5,32 +5,35 @@ 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; class DataExplorerView extends React.Component { - 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 ( ); @@ -46,14 +49,19 @@ class DataExplorerView extends React.Component { - 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(getCollectionList(item.uuid)); } } export default connect( (state: RootState) => ({ - projects: state.projects + projects: state.projects, + collections: state.collections }) )(DataExplorerView); diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx index 41725b53..c981c902 100644 --- a/src/views/workbench/workbench.tsx +++ b/src/views/workbench/workbench.tsx @@ -20,6 +20,7 @@ import { TreeItem, TreeItemStatus } from "../../components/tree/tree"; 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; @@ -122,7 +123,6 @@ class Workbench extends React.Component { } }; - mainAppBarActions: MainAppBarActionProps = { onBreadcrumbClick: ({ itemId, status }: NavBreadcrumb) => { this.toggleProjectTreeItem(itemId, status); @@ -141,6 +141,7 @@ class Workbench extends React.Component { this.props.dispatch(getProjectList(itemId)) .then(() => this.openProjectItem(itemId)); } + this.props.dispatch(getCollectionList(itemId)); } openProjectItem = (itemId: string) => { @@ -183,7 +184,7 @@ class Workbench extends React.Component {
- +
diff --git a/tslint.json b/tslint.json index 4845e4d2..7f02975d 100644 --- a/tslint.json +++ b/tslint.json @@ -12,7 +12,8 @@ "no-debugger": false, "no-console": false, "no-shadowed-variable": false, - "semicolon": true + "semicolon": true, + "array-type": false }, "linterOptions": { "exclude": [