From: Daniel Kos Date: Tue, 26 Jun 2018 10:20:38 +0000 (+0200) Subject: refs #13666 Merge branch 'origin/13666-data-explorer-mapper' X-Git-Tag: 1.2.0~67 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/4beb141298fce3da40f07e1a0a08f29ac28dfd09?hp=0af46f7944bde95f634080a1d6b15ae9c585890a refs #13666 Merge branch 'origin/13666-data-explorer-mapper' Arvados-DCO-1.1-Signed-off-by: Daniel Kos Arvados-DCO-1.1-Signed-off-by: Daniel Kos --- diff --git a/src/index.tsx b/src/index.tsx index ba395e8b..bc9f903d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -19,7 +19,11 @@ import { getProjectList } from "./store/project/project-action"; const history = createBrowserHistory(); const store = configureStore({ - projects: [ + projects: { + items: [], + currentItemId: "" + }, + collections: [ ], router: { location: null diff --git a/src/models/resource.ts b/src/models/resource.ts index 39b4e915..28bb349d 100644 --- a/src/models/resource.ts +++ b/src/models/resource.ts @@ -1,3 +1,7 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + export interface Resource { name: string; createdAt: string; @@ -5,5 +9,23 @@ export interface Resource { uuid: string; ownerUuid: string; href: string; - kind: string; + kind: ResourceKind; +} + +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/services/auth-service/auth-service.ts b/src/services/auth-service/auth-service.ts index d71f0299..e953a75d 100644 --- a/src/services/auth-service/auth-service.ts +++ b/src/services/auth-service/auth-service.ts @@ -35,6 +35,10 @@ export default class AuthService { return localStorage.getItem(API_TOKEN_KEY) || undefined; } + public getUuid() { + return localStorage.getItem(USER_UUID_KEY) || undefined; + } + public getOwnerUuid() { return localStorage.getItem(USER_OWNER_UUID_KEY) || undefined; } diff --git a/src/services/collection-service/collection-service.ts b/src/services/collection-service/collection-service.ts index 171cd856..bc912817 100644 --- a/src/services/collection-service/collection-service.ts +++ b/src/services/collection-service/collection-service.ts @@ -6,6 +6,7 @@ import { serverApi } from "../../common/api/server-api"; import FilterBuilder, { FilterField } from "../../common/api/filter-builder"; import { ArvadosResource } from "../response"; import { Collection } from "../../models/collection"; +import { getResourceKind } from "../../models/resource"; interface CollectionResource extends ArvadosResource { name: string; @@ -42,7 +43,7 @@ export default class CollectionService { href: g.href, uuid: g.uuid, ownerUuid: g.owner_uuid, - kind: g.kind + kind: getResourceKind(g.kind) } as Collection)); return collections; }); diff --git a/src/services/project-service/project-service.ts b/src/services/project-service/project-service.ts index bc340818..5bfa5449 100644 --- a/src/services/project-service/project-service.ts +++ b/src/services/project-service/project-service.ts @@ -7,6 +7,7 @@ import { Dispatch } from "redux"; import { Project } from "../../models/project"; import FilterBuilder, { FilterField } from "../../common/api/filter-builder"; import { ArvadosResource } from "../response"; +import { getResourceKind } from "../../models/resource"; interface GroupResource extends ArvadosResource { name: string; @@ -39,7 +40,7 @@ export default class ProjectService { href: g.href, uuid: g.uuid, ownerUuid: g.owner_uuid, - kind: g.kind + kind: getResourceKind(g.kind) } as Project)); return projects; }); diff --git a/src/store/collection/collection-reducer.test.ts b/src/store/collection/collection-reducer.test.ts index 7b57ba72..7bc1aec9 100644 --- a/src/store/collection/collection-reducer.test.ts +++ b/src/store/collection/collection-reducer.test.ts @@ -4,6 +4,7 @@ import collectionsReducer from "./collection-reducer"; import actions from "./collection-action"; +import { ResourceKind } from "../../models/resource"; describe('collection-reducer', () => { it('should add new collection to the list', () => { @@ -15,7 +16,7 @@ describe('collection-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: "" + kind: ResourceKind.COLLECTION }; const state = collectionsReducer(initialState, actions.CREATE_COLLECTION(collection)); @@ -31,7 +32,7 @@ describe('collection-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: "" + kind: ResourceKind.COLLECTION }; const collections = [collection, collection]; diff --git a/src/store/collection/collection-reducer.ts b/src/store/collection/collection-reducer.ts index 939ca625..5c257ea4 100644 --- a/src/store/collection/collection-reducer.ts +++ b/src/store/collection/collection-reducer.ts @@ -13,7 +13,7 @@ const collectionsReducer = (state: CollectionState = [], action: CollectionActio CREATE_COLLECTION: collection => [...state, collection], REMOVE_COLLECTION: () => state, COLLECTIONS_REQUEST: () => { - return state; + return []; }, COLLECTIONS_SUCCESS: ({ collections }) => { return collections; diff --git a/src/store/navigation/navigation-action.ts b/src/store/navigation/navigation-action.ts new file mode 100644 index 00000000..0b4bcdf8 --- /dev/null +++ b/src/store/navigation/navigation-action.ts @@ -0,0 +1,63 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { Dispatch } from "redux"; +import projectActions, { getProjectList } from "../project/project-action"; +import { push } from "react-router-redux"; +import { TreeItem, TreeItemStatus } from "../../components/tree/tree"; +import { getCollectionList } from "../collection/collection-action"; +import { findTreeItem } from "../project/project-reducer"; +import { Project } from "../../models/project"; +import { Resource, ResourceKind } from "../../models/resource"; +import sidePanelActions from "../side-panel/side-panel-action"; + +export const getResourceUrl = (resource: Resource): string => { + switch (resource.kind) { + case ResourceKind.LEVEL_UP: return `/projects/${resource.ownerUuid}`; + case ResourceKind.PROJECT: return `/projects/${resource.uuid}`; + case ResourceKind.COLLECTION: return `/collections/${resource.uuid}`; + default: + return "#"; + } +}; + +export enum ItemMode { + BOTH, + OPEN, + ACTIVE +} + +export const setProjectItem = (projects: Array>, itemId: string, itemKind: ResourceKind, itemMode: ItemMode) => (dispatch: Dispatch) => { + + const openProjectItem = (resource: Resource) => { + if (itemMode === ItemMode.OPEN || itemMode === ItemMode.BOTH) { + dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(resource.uuid)); + } + + if (itemMode === ItemMode.ACTIVE || itemMode === ItemMode.BOTH) { + dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(resource.uuid)); + } + + dispatch(push(getResourceUrl({...resource, kind: itemKind}))); + }; + + let treeItem = findTreeItem(projects, itemId); + if (treeItem && itemKind === ResourceKind.LEVEL_UP) { + treeItem = findTreeItem(projects, treeItem.data.ownerUuid); + } + + if (treeItem) { + dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(treeItem.data.uuid)); + + if (treeItem.status === TreeItemStatus.Loaded) { + openProjectItem(treeItem.data); + } else { + dispatch(getProjectList(itemId)) + .then(() => openProjectItem(treeItem!.data)); + } + if (itemMode === ItemMode.ACTIVE || itemMode === ItemMode.BOTH) { + dispatch(getCollectionList(itemId)); + } + } +}; diff --git a/src/store/project/project-reducer.test.ts b/src/store/project/project-reducer.test.ts index e8d6afc6..65a856bd 100644 --- a/src/store/project/project-reducer.test.ts +++ b/src/store/project/project-reducer.test.ts @@ -5,6 +5,7 @@ import projectsReducer, { getTreePath } from "./project-reducer"; import actions from "./project-action"; import { TreeItem, TreeItemStatus } from "../../components/tree/tree"; +import { ResourceKind } from "../../models/resource"; describe('project-reducer', () => { it('should add new project to the list', () => { @@ -16,7 +17,7 @@ describe('project-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: "" + kind: ResourceKind.PROJECT }; const state = projectsReducer(initialState, actions.CREATE_PROJECT(project)); @@ -32,7 +33,7 @@ describe('project-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: "" + kind: ResourceKind.PROJECT }; const projects = [project, project]; @@ -56,8 +57,8 @@ describe('project-reducer', () => { }); it('should remove activity on projects list', () => { - const initialState = [ - { + const initialState = { + items: [{ data: { name: 'test', href: 'href', @@ -65,16 +66,17 @@ describe('project-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: 'example' + kind: ResourceKind.PROJECT }, id: "1", open: true, active: true, status: 1 - } - ]; - const project = [ - { + }], + currentItemId: "1" + }; + const project = { + items: [{ data: { name: 'test', href: 'href', @@ -82,22 +84,23 @@ describe('project-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: 'example' + kind: ResourceKind.PROJECT }, id: "1", open: true, active: false, status: 1 - } - ]; + }], + currentItemId: "1" + }; const state = projectsReducer(initialState, actions.RESET_PROJECT_TREE_ACTIVITY(initialState[0].id)); expect(state).toEqual(project); }); it('should toggle project tree item activity', () => { - const initialState = [ - { + const initialState = { + items: [{ data: { name: 'test', href: 'href', @@ -105,16 +108,17 @@ describe('project-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: 'example' + kind: ResourceKind.PROJECT }, id: "1", open: true, active: false, status: 1 - } - ]; - const project = [ - { + }], + currentItemId: "1" + }; + const project = { + items: [{ data: { name: 'test', href: 'href', @@ -122,14 +126,15 @@ describe('project-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: 'example' + kind: ResourceKind.PROJECT }, id: "1", open: true, active: true, status: 1 - } - ]; + }], + currentItemId: "1" + }; const state = projectsReducer(initialState, actions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(initialState[0].id)); expect(state).toEqual(project); @@ -137,8 +142,8 @@ describe('project-reducer', () => { it('should close project tree item ', () => { - const initialState = [ - { + const initialState = { + items: [{ data: { name: 'test', href: 'href', @@ -146,17 +151,18 @@ describe('project-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: 'example' + kind: ResourceKind.PROJECT }, id: "1", open: true, active: false, status: 1, toggled: false, - } - ]; - const project = [ - { + }], + currentItemId: "1" + }; + const project = { + items: [{ data: { name: 'test', href: 'href', @@ -164,15 +170,16 @@ describe('project-reducer', () => { modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', uuid: 'test123', - kind: 'example' + kind: ResourceKind.PROJECT }, id: "1", open: false, active: false, status: 1, toggled: true - } - ]; + }], + currentItemId: "1" + }; const state = projectsReducer(initialState, actions.TOGGLE_PROJECT_TREE_ITEM_OPEN(initialState[0].id)); expect(state).toEqual(project); @@ -180,7 +187,6 @@ describe('project-reducer', () => { }); describe("findTreeBranch", () => { - const createTreeItem = (id: string, items?: Array>): TreeItem => ({ id, items, diff --git a/src/store/project/project-reducer.ts b/src/store/project/project-reducer.ts index 48db05df..0e2018b4 100644 --- a/src/store/project/project-reducer.ts +++ b/src/store/project/project-reducer.ts @@ -8,7 +8,10 @@ import { Project } from "../../models/project"; import actions, { ProjectAction } from "./project-action"; import { TreeItem, TreeItemStatus } from "../../components/tree/tree"; -export type ProjectState = Array>; +export type ProjectState = { + items: Array>, + currentItemId: string +}; export function findTreeItem(tree: Array>, itemId: string): TreeItem | undefined { let item; @@ -23,8 +26,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 { @@ -52,7 +68,7 @@ function updateProjectTree(tree: Array>, projects: Project[], treeItem.status = TreeItemStatus.Loaded; } } - const items = projects.map((p, idx) => ({ + const items = projects.map(p => ({ id: p.uuid, open: false, active: false, @@ -69,43 +85,67 @@ function updateProjectTree(tree: Array>, projects: Project[], return items; } -const projectsReducer = (state: ProjectState = [], action: ProjectAction) => { +const projectsReducer = (state: ProjectState = { items: [], currentItemId: "" }, action: ProjectAction) => { return actions.match(action, { - CREATE_PROJECT: project => [...state, project], + CREATE_PROJECT: project => ({ + ...state, + items: state.items.concat({ + id: project.uuid, + open: false, + active: false, + status: TreeItemStatus.Loaded, + toggled: false, + items: [], + data: project + }) + }), REMOVE_PROJECT: () => state, PROJECTS_REQUEST: itemId => { - const tree = _.cloneDeep(state); - const item = findTreeItem(tree, itemId); + const items = _.cloneDeep(state.items); + const item = findTreeItem(items, itemId); if (item) { item.status = TreeItemStatus.Pending; + state.items = items; } - return tree; + return state; }, PROJECTS_SUCCESS: ({ projects, parentItemId }) => { - return updateProjectTree(state, projects, parentItemId); + return { + ...state, + items: updateProjectTree(state.items, projects, parentItemId) + }; }, TOGGLE_PROJECT_TREE_ITEM_OPEN: itemId => { - const tree = _.cloneDeep(state); - const item = findTreeItem(tree, itemId); + const items = _.cloneDeep(state.items); + const item = findTreeItem(items, itemId); if (item) { item.toggled = true; item.open = !item.open; } - return tree; + return { + items, + currentItemId: itemId + }; }, TOGGLE_PROJECT_TREE_ITEM_ACTIVE: itemId => { - const tree = _.cloneDeep(state); - resetTreeActivity(tree); - const item = findTreeItem(tree, itemId); + const items = _.cloneDeep(state.items); + resetTreeActivity(items); + const item = findTreeItem(items, itemId); if (item) { item.active = true; } - return tree; + return { + items, + currentItemId: itemId + }; }, RESET_PROJECT_TREE_ACTIVITY: () => { - const tree = _.cloneDeep(state); - resetTreeActivity(tree); - return tree; + const items = _.cloneDeep(state.items); + resetTreeActivity(items); + return { + items, + currentItemId: "" + }; }, default: () => state }); diff --git a/src/store/store.ts b/src/store/store.ts index 6089caf3..40b24a04 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -10,7 +10,7 @@ import { History } from "history"; import projectsReducer, { ProjectState } from "./project/project-reducer"; import sidePanelReducer, { SidePanelState } from './side-panel/side-panel-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' && @@ -20,6 +20,7 @@ const composeEnhancers = export interface RootState { auth: AuthState; projects: ProjectState; + collections: CollectionState; router: RouterState; sidePanel: SidePanelState; } diff --git a/src/views-components/project-explorer/project-explorer-item.ts b/src/views-components/project-explorer/project-explorer-item.ts index 055c22cf..4fa3d3d6 100644 --- a/src/views-components/project-explorer/project-explorer-item.ts +++ b/src/views-components/project-explorer/project-explorer-item.ts @@ -2,12 +2,26 @@ // // SPDX-License-Identifier: AGPL-3.0 +import { getResourceKind, Resource, ResourceKind } from "../../models/resource"; + export interface ProjectExplorerItem { uuid: string; name: string; - type: string; + kind: ResourceKind; + url: string; owner: string; lastModified: string; fileSize?: number; status?: string; } + +function resourceToDataItem(r: Resource, kind?: ResourceKind) { + return { + uuid: r.uuid, + name: r.name, + kind: kind ? kind : getResourceKind(r.kind), + owner: r.ownerUuid, + lastModified: r.modifiedAt + }; +} + diff --git a/src/views-components/project-explorer/project-explorer.tsx b/src/views-components/project-explorer/project-explorer.tsx index 4931c09a..1018ef5e 100644 --- a/src/views-components/project-explorer/project-explorer.tsx +++ b/src/views-components/project-explorer/project-explorer.tsx @@ -10,6 +10,7 @@ import DataExplorer from '../../components/data-explorer/data-explorer'; import { DataColumn, toggleSortDirection, resetSortDirection } from '../../components/data-table/data-column'; import { DataTableFilterItem } from '../../components/data-table-filters/data-table-filters'; import { ContextMenuAction } from '../../components/context-menu/context-menu'; +import { ResourceKind } from "../../models/resource"; export interface ProjectExplorerContextActions { onAddToFavourite: (item: ProjectExplorerItem) => void; @@ -23,6 +24,7 @@ export interface ProjectExplorerContextActions { interface ProjectExplorerProps { items: ProjectExplorerItem[]; + onRowClick: (item: ProjectExplorerItem) => void; } interface ProjectExplorerState { @@ -63,7 +65,7 @@ class ProjectExplorer extends React.Component renderType(item.type) + render: item => renderType(item.kind) }, { name: "Owner", selected: true, @@ -114,7 +116,7 @@ class ProjectExplorer extends React.Component ; + const renderIcon = (item: ProjectExplorerItem) => { - switch (item.type) { - case "arvados#group": - return ; - case "arvados#groupList": - return ; + switch (item.kind) { + case ResourceKind.LEVEL_UP: + return ; + case ResourceKind.PROJECT: + return ; + case ResourceKind.COLLECTION: + return ; default: return ; } diff --git a/src/views/project-panel/project-panel-selectors.ts b/src/views/project-panel/project-panel-selectors.ts index 610f2fa9..c798ec3d 100644 --- a/src/views/project-panel/project-panel-selectors.ts +++ b/src/views/project-panel/project-panel-selectors.ts @@ -4,12 +4,55 @@ import { TreeItem } from "../../components/tree/tree"; import { Project } from "../../models/project"; +import { findTreeItem } from "../../store/project/project-reducer"; +import { ResourceKind } from "../../models/resource"; +import { Collection } from "../../models/collection"; +import { getResourceUrl } from "../../store/navigation/navigation-action"; import { ProjectExplorerItem } from "../../views-components/project-explorer/project-explorer-item"; -export const mapProjectTreeItem = (item: TreeItem): ProjectExplorerItem => ({ - name: item.data.name, - type: item.data.kind, - owner: item.data.ownerUuid, - lastModified: item.data.modifiedAt, - uuid: item.data.uuid -}); +export const projectExplorerItems = (projects: Array>, treeItemId: string, collections: Array): ProjectExplorerItem[] => { + const dataItems: ProjectExplorerItem[] = []; + + const treeItem = findTreeItem(projects, treeItemId); + if (treeItem) { + dataItems.push({ + name: "..", + url: getResourceUrl(treeItem.data), + kind: 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, + kind: ResourceKind.PROJECT, + url: getResourceUrl(treeItem.data), + owner: p.data.ownerUuid, + uuid: p.data.uuid, + lastModified: p.data.modifiedAt + } as ProjectExplorerItem; + + dataItems.push(item); + }); + } + } + + collections.forEach(c => { + const item = { + name: c.name, + kind: ResourceKind.COLLECTION, + url: getResourceUrl(c), + owner: c.ownerUuid, + uuid: c.uuid, + lastModified: c.modifiedAt + } as ProjectExplorerItem; + + dataItems.push(item); + }); + + return dataItems; +}; + diff --git a/src/views/project-panel/project-panel.tsx b/src/views/project-panel/project-panel.tsx index f9e6c8b8..534f843f 100644 --- a/src/views/project-panel/project-panel.tsx +++ b/src/views/project-panel/project-panel.tsx @@ -3,32 +3,46 @@ // SPDX-License-Identifier: AGPL-3.0 import * as React from 'react'; -import { RouteComponentProps } from 'react-router-dom'; -import { DispatchProp, connect } from 'react-redux'; -import { ProjectState, findTreeItem } from '../../store/project/project-reducer'; -import ProjectExplorer from '../../views-components/project-explorer/project-explorer'; +import { RouteComponentProps } from 'react-router'; +import { ProjectState } from '../../store/project/project-reducer'; import { RootState } from '../../store/store'; -import { mapProjectTreeItem } from './project-panel-selectors'; +import { connect, DispatchProp } from 'react-redux'; +import { CollectionState } from "../../store/collection/collection-reducer"; +import { ItemMode, setProjectItem } from "../../store/navigation/navigation-action"; +import ProjectExplorer from "../../views-components/project-explorer/project-explorer"; +import { projectExplorerItems } from "./project-panel-selectors"; +import { ProjectExplorerItem } from "../../views-components/project-explorer/project-explorer-item"; interface ProjectPanelDataProps { projects: ProjectState; + collections: CollectionState; } type ProjectPanelProps = ProjectPanelDataProps & RouteComponentProps<{ name: string }> & DispatchProp; class ProjectPanel extends React.Component { - render() { - const project = findTreeItem(this.props.projects, this.props.match.params.name); - const projectItems = project && project.items || []; + const items = projectExplorerItems( + this.props.projects.items, + this.props.projects.currentItemId, + this.props.collections + ); return ( - + ); } + + goToItem = (item: ProjectExplorerItem) => { + this.props.dispatch(setProjectItem(this.props.projects.items, item.uuid, item.kind, ItemMode.BOTH)); + } } export default connect( (state: RootState) => ({ - projects: state.projects + projects: state.projects, + collections: state.collections }) )(ProjectPanel); diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx index 4f9843cb..1069de53 100644 --- a/src/views/workbench/workbench.tsx +++ b/src/views/workbench/workbench.tsx @@ -10,18 +10,22 @@ import { Route, Switch } from "react-router"; import authActions from "../../store/auth/auth-action"; import { User } from "../../models/user"; import { RootState } from "../../store/store"; -import MainAppBar, { MainAppBarActionProps, MainAppBarMenuItem } from '../../views-components/main-app-bar/main-app-bar'; +import MainAppBar, { + MainAppBarActionProps, + MainAppBarMenuItem +} from '../../views-components/main-app-bar/main-app-bar'; import { Breadcrumb } from '../../components/breadcrumbs/breadcrumbs'; import { push } from 'react-router-redux'; -import projectActions, { getProjectList } from "../../store/project/project-action"; import ProjectTree from '../../views-components/project-tree/project-tree'; -import { TreeItem, TreeItemStatus } from "../../components/tree/tree"; +import { TreeItem } from "../../components/tree/tree"; import { Project } from "../../models/project"; import { getTreePath } from '../../store/project/project-reducer'; import ProjectPanel from '../project-panel/project-panel'; import sidePanelActions from '../../store/side-panel/side-panel-action'; -import { projectService } from '../../services/services'; import SidePanel, { SidePanelItem } from '../../components/side-panel/side-panel'; +import { ResourceKind } from "../../models/resource"; +import { ItemMode, setProjectItem } from "../../store/navigation/navigation-action"; +import projectActions from "../../store/project/project-action"; const drawerWidth = 240; const appBarHeight = 102; @@ -67,6 +71,7 @@ const styles: StyleRulesCallback = (theme: Theme) => ({ interface WorkbenchDataProps { projects: Array>; + currentProjectId: string; user?: User; sidePanelItems: SidePanelItem[]; } @@ -78,7 +83,6 @@ type WorkbenchProps = WorkbenchDataProps & WorkbenchActionProps & DispatchProp & interface NavBreadcrumb extends Breadcrumb { itemId: string; - status: TreeItemStatus; } interface NavMenuItem extends MainAppBarMenuItem { @@ -87,7 +91,6 @@ interface NavMenuItem extends MainAppBarMenuItem { interface WorkbenchState { anchorEl: any; - breadcrumbs: NavBreadcrumb[]; searchText: string; menuItems: { accountMenu: NavMenuItem[], @@ -127,10 +130,11 @@ class Workbench extends React.Component { } }; - mainAppBarActions: MainAppBarActionProps = { - onBreadcrumbClick: ({ itemId, status }: NavBreadcrumb) => { - this.toggleProjectTreeItemOpen(itemId, status); + onBreadcrumbClick: ({ itemId }: NavBreadcrumb) => { + this.props.dispatch( + setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT, ItemMode.BOTH) + ); }, onSearch: searchText => { this.setState({ searchText }); @@ -139,36 +143,6 @@ class Workbench extends React.Component { onMenuItemClick: (menuItem: NavMenuItem) => menuItem.action() }; - toggleProjectTreeItemOpen = (itemId: string, status: TreeItemStatus) => { - if (status === TreeItemStatus.Loaded) { - this.openProjectItem(itemId); - this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId)); - this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId)); - } else { - this.props.dispatch(getProjectList(itemId)) - .then(() => { - this.openProjectItem(itemId); - this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId)); - this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId)); - }); - } - } - - toggleProjectTreeItemActive = (itemId: string, status: TreeItemStatus) => { - if (status === TreeItemStatus.Loaded) { - this.openProjectItem(itemId); - this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId)); - this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId)); - } else { - this.props.dispatch(getProjectList(itemId)) - .then(() => { - this.openProjectItem(itemId); - this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId)); - this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId)); - }); - } - } - toggleSidePanelOpen = (itemId: string) => { this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(itemId)); } @@ -178,26 +152,20 @@ class Workbench extends React.Component { this.props.dispatch(projectActions.RESET_PROJECT_TREE_ACTIVITY(itemId)); } - openProjectItem = (itemId: string) => { - const branch = getTreePath(this.props.projects, itemId); - this.setState({ - breadcrumbs: branch.map(item => ({ - label: item.data.name, - itemId: item.data.uuid, - status: item.status - })) - }); - this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId)); - this.props.dispatch(push(`/project/${itemId}`)); - } - render() { - const { classes, user, projects, sidePanelItems } = this.props; + const branch = getTreePath(this.props.projects, this.props.currentProjectId); + const breadcrumbs = branch.map(item => ({ + label: item.data.name, + itemId: item.data.uuid, + status: item.status + })); + + const { classes, user } = this.props; return (
{ + sidePanelItems={this.props.sidePanelItems}> + projects={this.props.projects} + toggleOpen={itemId => + this.props.dispatch( + setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT, ItemMode.OPEN) + )} + toggleActive={itemId => + this.props.dispatch( + setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT, ItemMode.ACTIVE) + )} + /> }
- +
@@ -235,9 +210,10 @@ class Workbench extends React.Component { export default connect( (state: RootState) => ({ - projects: state.projects, + projects: state.projects.items, + currentProjectId: state.projects.currentItemId, user: state.auth.user, - sidePanelItems: state.sidePanel, + sidePanelItems: state.sidePanel }) )( withStyles(styles)(Workbench) diff --git a/tslint.json b/tslint.json index 4845e4d2..0ddfc627 100644 --- a/tslint.json +++ b/tslint.json @@ -12,7 +12,9 @@ "no-debugger": false, "no-console": false, "no-shadowed-variable": false, - "semicolon": true + "semicolon": true, + "array-type": false, + "interface-over-type-literal": false }, "linterOptions": { "exclude": [