From: Michal Klobukowski Date: Mon, 18 Jun 2018 11:03:22 +0000 (+0200) Subject: Merge branch 'master' X-Git-Tag: 1.2.0~74^2~1 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/4bbaf2a0cede89ea50d63d210c6631adc1970620?hp=-c Merge branch 'master' Feature #13628 Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski --- 4bbaf2a0cede89ea50d63d210c6631adc1970620 diff --combined src/store/project/project-reducer.test.ts index 3e828830,cfb73fa8..311ec9d1 --- a/src/store/project/project-reducer.test.ts +++ b/src/store/project/project-reducer.test.ts @@@ -2,9 -2,8 +2,9 @@@ // // SPDX-License-Identifier: AGPL-3.0 -import projectsReducer from "./project-reducer"; +import projectsReducer, { findTreeBranch } from "./project-reducer"; import actions from "./project-action"; - import { TreeItem } from "../../components/tree/tree"; ++import { TreeItem, TreeItemStatus } from "../../components/tree/tree"; describe('project-reducer', () => { it('should add new project to the list', () => { @@@ -15,7 -14,8 +15,8 @@@ createdAt: '2018-01-01', modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', - uuid: 'test123' + uuid: 'test123', + kind: "" }; const state = projectsReducer(initialState, actions.CREATE_PROJECT(project)); @@@ -30,73 -30,27 +31,77 @@@ createdAt: '2018-01-01', modifiedAt: '2018-01-01', ownerUuid: 'owner-test123', - uuid: 'test123' + uuid: 'test123', + kind: "" }; const projects = [project, project]; - const state = projectsReducer(initialState, actions.PROJECTS_SUCCESS({projects, parentItemId: undefined})); + const state = projectsReducer(initialState, actions.PROJECTS_SUCCESS({ projects, parentItemId: undefined })); expect(state).toEqual([{ - active: false, - open: false, - id: "test123", - items: [], - data: project - }, { - active: false, - open: false, - id: "test123", - items: [], - data: project - } + active: false, + open: false, + id: "test123", + items: [], + data: project, + status: 0 + }, { + active: false, + open: false, + id: "test123", + items: [], + data: project, + status: 0 + } ]); }); }); + +describe("findTreeBranch", () => { + + const createTreeItem = (id: string, items?: Array>): TreeItem => ({ + id, + items, + active: false, + data: "", + open: false, ++ status: TreeItemStatus.Initial + }); + + it("should return an array that matches path to the given item", () => { + const tree: Array> = [ + createTreeItem("1", [ + createTreeItem("1.1", [ + createTreeItem("1.1.1"), + createTreeItem("1.1.2") + ]) + ]), + createTreeItem("2", [ + createTreeItem("2.1", [ + createTreeItem("2.1.1"), + createTreeItem("2.1.2") + ]) + ]) + ]; + const branch = findTreeBranch(tree, "2.1.1"); + expect(branch.map(item => item.id)).toEqual(["2", "2.1", "2.1.1"]); + }); + + it("should return empty array if item is not found", () => { + const tree: Array> = [ + createTreeItem("1", [ + createTreeItem("1.1", [ + createTreeItem("1.1.1"), + createTreeItem("1.1.2") + ]) + ]), + createTreeItem("2", [ + createTreeItem("2.1", [ + createTreeItem("2.1.1"), + createTreeItem("2.1.2") + ]) + ]) + ]; + expect(findTreeBranch(tree, "3")).toHaveLength(0); + }); + +}); diff --combined src/store/project/project-reducer.ts index ac6d4b73,7563ea90..8770391a --- a/src/store/project/project-reducer.ts +++ b/src/store/project/project-reducer.ts @@@ -4,12 -4,12 +4,12 @@@ import { Project } from "../../models/project"; import actions, { ProjectAction } from "./project-action"; - import { TreeItem } from "../../components/tree/tree"; + import { TreeItem, TreeItemStatus } from "../../components/tree/tree"; import * as _ from "lodash"; export type ProjectState = Array>; - function findTreeItem(tree: Array>, itemId: string): TreeItem | undefined { + export function findTreeItem(tree: Array>, itemId: string): TreeItem | undefined { let item; for (const t of tree) { item = t.id === itemId @@@ -22,20 -22,6 +22,20 @@@ return item; } +export function findTreeBranch(tree: Array>, itemId: string): Array> { + for(const item of tree){ + if(item.id === itemId){ + return [item]; + } else { + const branch = findTreeBranch(item.items || [], itemId); + if(branch.length > 0){ + return [item, ...branch]; + } + } + } + return []; +} + function resetTreeActivity(tree: Array>) { for (const t of tree) { t.active = false; @@@ -47,11 -33,15 +47,15 @@@ function updateProjectTree(tree: Array< let treeItem; if (parentItemId) { treeItem = findTreeItem(tree, parentItemId); + if (treeItem) { + treeItem.status = TreeItemStatus.Loaded; + } } const items = projects.map((p, idx) => ({ id: p.uuid, open: false, active: false, + status: TreeItemStatus.Initial, data: p, items: [] } as TreeItem)); @@@ -64,12 -54,18 +68,18 @@@ return items; } - const projectsReducer = (state: ProjectState = [], action: ProjectAction) => { return actions.match(action, { CREATE_PROJECT: project => [...state, project], REMOVE_PROJECT: () => state, - PROJECTS_REQUEST: () => state, + PROJECTS_REQUEST: itemId => { + const tree = _.cloneDeep(state); + const item = findTreeItem(tree, itemId); + if (item) { + item.status = TreeItemStatus.Pending; + } + return tree; + }, PROJECTS_SUCCESS: ({ projects, parentItemId }) => { return updateProjectTree(state, projects, parentItemId); }, @@@ -80,6 -76,7 +90,7 @@@ if (item) { item.open = !item.open; item.active = true; + item.toggled = true; } return tree; }, diff --combined src/views/workbench/workbench.tsx index cb691869,90df260b..0aecc0d2 --- a/src/views/workbench/workbench.tsx +++ b/src/views/workbench/workbench.tsx @@@ -6,31 -6,20 +6,21 @@@ import * as React from 'react' import { StyleRulesCallback, Theme, WithStyles, withStyles } from '@material-ui/core/styles'; import Drawer from '@material-ui/core/Drawer'; - import AppBar from '@material-ui/core/AppBar'; - import Toolbar from '@material-ui/core/Toolbar'; - import Typography from '@material-ui/core/Typography'; import { connect, DispatchProp } from "react-redux"; - import ProjectList from "../../components/project-list/project-list"; import { Route, Switch } from "react-router"; - import { Link } from "react-router-dom"; - import Button from "@material-ui/core/Button/Button"; import authActions from "../../store/auth/auth-action"; - import IconButton from "@material-ui/core/IconButton/IconButton"; - import Menu from "@material-ui/core/Menu/Menu"; - import MenuItem from "@material-ui/core/MenuItem/MenuItem"; - import { AccountCircle } from "@material-ui/icons"; import { User } from "../../models/user"; - import Grid from "@material-ui/core/Grid/Grid"; import { RootState } from "../../store/store"; - import MainAppBar, { MainAppBarActionProps, MainAppBarMenuItems, MainAppBarMenuItem } from '../../components/main-app-bar/main-app-bar'; + import MainAppBar, { MainAppBarActionProps, MainAppBarMenuItem } from '../../components/main-app-bar/main-app-bar'; import { Breadcrumb } from '../../components/breadcrumbs/breadcrumbs'; import { push } from 'react-router-redux'; import projectActions from "../../store/project/project-action"; import ProjectTree from '../../components/project-tree/project-tree'; - import { TreeItem } from "../../components/tree/tree"; + import { TreeItem, TreeItemStatus } from "../../components/tree/tree"; import { Project } from "../../models/project"; import { projectService } from '../../services/services'; +import { findTreeBranch } from '../../store/project/project-reducer'; + import DataExplorer from '../data-explorer/data-explorer'; const drawerWidth = 240; @@@ -77,7 -66,7 +67,8 @@@ interface WorkbenchActionProps type WorkbenchProps = WorkbenchDataProps & WorkbenchActionProps & DispatchProp & WithStyles; interface NavBreadcrumb extends Breadcrumb { - path: string; + itemId: string; ++ status: TreeItemStatus; } interface NavMenuItem extends MainAppBarMenuItem { @@@ -99,7 -88,15 +90,7 @@@ class Workbench extends React.Component state = { anchorEl: null, searchText: "", - breadcrumbs: [ - { - label: "Projects", - path: "/projects" - }, { - label: "Project 1", - path: "/projects/project-1" - } - ], + breadcrumbs: [], menuItems: { accountMenu: [ { @@@ -128,9 -125,7 +119,9 @@@ mainAppBarActions: MainAppBarActionProps = { - onBreadcrumbClick: ({ itemId }: NavBreadcrumb) => { - this.toggleProjectTreeItem(itemId); - onBreadcrumbClick: (breadcrumb: NavBreadcrumb) => this.props.dispatch(push(breadcrumb.path)), ++ onBreadcrumbClick: ({ itemId, status }: NavBreadcrumb) => { ++ this.toggleProjectTreeItem(itemId, status); + }, onSearch: searchText => { this.setState({ searchText }); this.props.dispatch(push(`/search?q=${searchText}`)); @@@ -138,17 -133,17 +129,25 @@@ onMenuItemClick: (menuItem: NavMenuItem) => menuItem.action() }; - toggleProjectTreeItem = (itemId: string) => { + toggleProjectTreeItem = (itemId: string, status: TreeItemStatus) => { + if (status === TreeItemStatus.Loaded) { + this.openProjectItem(itemId); + } else { + this.props.dispatch(projectService.getProjectList(itemId)).then(() => this.openProjectItem(itemId)); + } + } + + openProjectItem = (itemId: string) => { + const branch = findTreeBranch(this.props.projects, itemId); + this.setState({ + breadcrumbs: branch.map(item => ({ + label: item.data.name, - itemId: item.data.uuid ++ itemId: item.data.uuid, ++ status: item.status + })) + }); - this.props.dispatch(projectService.getProjectList(itemId)).then(() => { - this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(itemId)); - }); + this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(itemId)); + this.props.dispatch(push(`/project/${itemId}`)); } render() { @@@ -179,7 -174,7 +178,7 @@@
- +