From: Daniel Kos Date: Tue, 12 Jun 2018 19:38:39 +0000 (+0200) Subject: refs #13535 Merge branch '13535-tree-component' into 13610-projects-hierarchy X-Git-Tag: 1.2.0~80^2~3 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/eeb82d50816250cc6287928e6d958affa73880ee refs #13535 Merge branch '13535-tree-component' into 13610-projects-hierarchy # Conflicts: # package.json # src/components/tree/tree.tsx # src/index.tsx # src/models/project.ts # src/store/project-action.ts # src/store/project-reducer.ts # src/views/workbench/workbench.test.tsx # src/views/workbench/workbench.tsx # tslint.json # yarn.lock Arvados-DCO-1.1-Signed-off-by: Daniel Kos --- eeb82d50816250cc6287928e6d958affa73880ee diff --cc package.json index ac890d8d,e4ba28ac..399750a3 --- a/package.json +++ b/package.json @@@ -3,11 -3,10 +3,12 @@@ "version": "0.1.0", "private": true, "dependencies": { - "@material-ui/core": "1.0.0", + "@material-ui/core": "1.2.0", + "@material-ui/icons": "^1.1.0", + "lodash": "4.17.10", - "react": "16.3.2", - "react-dom": "16.3.2", + "axios": "0.18.0", + "react": "16.4.0", + "react-dom": "16.4.0", "react-redux": "5.0.7", "react-router": "4.2.0", "react-router-dom": "4.2.2", @@@ -25,18 -24,21 +26,22 @@@ "lint": "tslint src/** -t verbose" }, "devDependencies": { + "@types/enzyme": "^3.1.10", + "@types/enzyme-adapter-react-16": "^1.0.2", - "@types/jest": "22.2.3", - "@types/lodash": "4.14.109", - "@types/node": "10.1.2", - "@types/react": "16.3.14", + "@types/jest": "23.0.0", + "@types/node": "10.3.0", + "@types/react": "16.3.16", "@types/react-dom": "16.0.5", - "@types/react-redux": "6.0.0", - "@types/react-router": "4.0.25", - "@types/react-router-dom": "4.2.6", - "@types/react-router-redux": "5.0.14", + "@types/react-redux": "6.0.1", + "@types/react-router": "4.0.26", + "@types/react-router-dom": "4.2.7", + "@types/react-router-redux": "5.0.15", "@types/redux-devtools": "3.0.44", + "enzyme": "^3.3.0", + "enzyme-adapter-react-16": "^1.1.1", - "typescript": "2.8.3" + "jest-localstorage-mock": "2.2.0", + "redux-devtools": "3.4.1", + "typescript": "2.9.1" }, "moduleNameMapper": { "^~/(.*)$": "/src/$1" diff --cc src/index.tsx index 0cb67f1d,9cc33feb..17329681 --- a/src/index.tsx +++ b/src/index.tsx @@@ -12,25 -12,51 +12,44 @@@ import { Route } from "react-router" import createBrowserHistory from "history/createBrowserHistory"; import configureStore from "./store/store"; import { ConnectedRouter } from "react-router-redux"; +import ApiToken from "./components/api-token/api-token"; +import authActions from "./store/auth/auth-action"; +import { projectService } from "./services/services"; + import { TreeItem } from "./components/tree/tree"; + import { Project } from "./models/project"; -const sampleProjects = [ - [ - 'Project 1', [ - ['Project 1.1', [['Project 1.1.1'], ['Project 1.1.2']]], - ['Project 1.2', [['Project 1.2.1'], ['Project 1.2.2'], ['Project 1.2.3']]] - ] - ], - [ - 'Project 2' - ], - [ - 'Project 3', [['Project 3.1'], ['Project 3.2']] - ] -]; - - + function buildProjectTree(tree: any[], level = 0): Array> { + const projects = tree.map((t, idx) => ({ + id: `l${level}i${idx}${t[0]}`, + open: false, + active: false, + data: { + name: t[0], + icon: level === 0 ? : , + createdAt: '2018-05-05', + }, + items: t.length > 1 ? buildProjectTree(t[1], level + 1) : [] + })); + return projects; + } - - const history = createBrowserHistory(); + const projects = buildProjectTree(sampleProjects); + const store = configureStore({ - projects, + projects: [ + ], router: { location: null + }, + auth: { + user: undefined } }, history); +store.dispatch(authActions.INIT()); +store.dispatch(projectService.getProjectList()); + ++ const App = () => diff --cc src/models/project.ts index 83862c94,d730bcdf..f4faf7d6 --- a/src/models/project.ts +++ b/src/models/project.ts @@@ -5,8 -5,5 +5,9 @@@ export interface Project { name: string; createdAt: string; + modifiedAt: string; + uuid: string; + ownerUuid: string; - href: string ++ href: string; + icon?: any; } diff --cc src/store/project/project-action.ts index c88edb60,00000000..21016195 mode 100644,000000..100644 --- a/src/store/project/project-action.ts +++ b/src/store/project/project-action.ts @@@ -1,19 -1,0 +1,20 @@@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { Project } from "../../models/project"; +import { default as unionize, ofType, UnionOf } from "unionize"; + +const actions = unionize({ + CREATE_PROJECT: ofType(), + REMOVE_PROJECT: ofType(), + PROJECTS_REQUEST: {}, - PROJECTS_SUCCESS: ofType() ++ PROJECTS_SUCCESS: ofType(), ++ TOGGLE_PROJECT_TREE_ITEM: ofType() +}, { + tag: 'type', + value: 'payload' +}); + +export type ProjectAction = UnionOf; +export default actions; diff --cc src/store/project/project-reducer.ts index 477cb1e4,00000000..458177c0 mode 100644,000000..100644 --- a/src/store/project/project-reducer.ts +++ b/src/store/project/project-reducer.ts @@@ -1,22 -1,0 +1,57 @@@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { Project } from "../../models/project"; +import actions, { ProjectAction } from "./project-action"; ++import { TreeItem } from "../../components/tree/tree"; ++import * as _ from "lodash"; + - export type ProjectState = Project[]; ++export type ProjectState = Array>; ++ ++function findTreeItem(tree: Array>, itemId: string): TreeItem | undefined { ++ let item; ++ for (const t of tree) { ++ item = t.id === itemId ++ ? t ++ : findTreeItem(t.items ? t.items : [], itemId); ++ if (item) { ++ break; ++ } ++ } ++ return item; ++} ++ ++function resetTreeActivity(tree: Array>): boolean | undefined { ++ let item; ++ for (const leaf of tree) { ++ item = leaf.active === true ++ ? leaf.active = false ++ : resetTreeActivity(leaf.items ? leaf.items : []); ++ } ++ return item; ++} + +const projectsReducer = (state: ProjectState = [], action: ProjectAction) => { + return actions.match(action, { + CREATE_PROJECT: project => [...state, project], + REMOVE_PROJECT: () => state, + PROJECTS_REQUEST: () => state, + PROJECTS_SUCCESS: projects => { + return projects; + }, ++ TOGGLE_PROJECT_TREE_ITEM: itemId => { ++ const tree = _.cloneDeep(state); ++ resetTreeActivity(tree); ++ const item = findTreeItem(tree, itemId); ++ if (item) { ++ item.open = !item.open; ++ item.active = true; ++ } ++ return tree; ++ }, + default: () => state + }); +}; + +export default projectsReducer; diff --cc src/views/workbench/workbench.test.tsx index fc89609a,b1657bc3..7b9b74d0 --- a/src/views/workbench/workbench.test.tsx +++ b/src/views/workbench/workbench.test.tsx @@@ -11,7 -14,13 +14,13 @@@ const history = createBrowserHistory() it('renders without crashing', () => { const div = document.createElement('div'); - const store = configureStore({ projects: [], router: { location: null } }, createBrowserHistory()); + const store = configureStore({ projects: [], router: { location: null }, auth: {} }, createBrowserHistory()); - ReactDOM.render(, div); + ReactDOM.render( + + + + + , + div); ReactDOM.unmountComponentAtNode(div); }); diff --cc src/views/workbench/workbench.tsx index 8c3145b8,6f39ac78..7cccfe30 --- a/src/views/workbench/workbench.tsx +++ b/src/views/workbench/workbench.tsx @@@ -15,16 -14,10 +15,19 @@@ import { Project } from "../../models/p 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 { actions as projectActions } from "../../store/project-action"; + import ProjectTree, { WorkbenchProps } from '../../components/project-tree/project-tree'; + const drawerWidth = 240; type CssRules = 'root' | 'appBar' | 'drawerPaper' | 'content' | 'toolbar'; @@@ -153,15 -66,18 +156,15 @@@ class Workbench extends React.Component classes={{ paper: classes.drawerPaper, }}> -
- - - {p.name} - }/> ++ - ++ toggleProjectTreeItem={this.props.toggleProjectTreeItem}/> + }
-
+
- - Hello new workbench! - - +
@@@ -169,11 -85,12 +172,13 @@@ } } -export default connect( +export default connect( (state: RootState) => ({ - projects: state.projects - }), { + projects: state.projects, + user: state.auth.user - }) ++ }){ + toggleProjectTreeItem: (id: string) => projectActions.toggleProjectTreeItem(id) + } )( withStyles(styles)(Workbench) ); diff --cc yarn.lock index 7b9820bb,eadc3467..f3950fae --- a/yarn.lock +++ b/yarn.lock @@@ -53,14 -52,26 +53,31 @@@ react-transition-group "^2.2.1" recompose "^0.26.0 || ^0.27.0" scroll "^2.0.3" - warning "^3.0.0" + warning "^4.0.1" + +"@material-ui/icons@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-1.1.0.tgz#4d025df7b0ba6ace8d6710079ed76013a4d26595" + dependencies: + recompose "^0.26.0 || ^0.27.0" + "@types/cheerio@*": + version "0.22.7" + resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce" + + "@types/enzyme-adapter-react-16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.2.tgz#15ae37c64d6221a6f4b3a4aacc357cf773859de4" + dependencies: + "@types/enzyme" "*" + + "@types/enzyme@*", "@types/enzyme@^3.1.10": + version "3.1.10" + resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.1.10.tgz#28108a9864e65699751469551a803a35d2e26160" + dependencies: + "@types/cheerio" "*" + "@types/react" "*" + "@types/history@*": version "4.6.2" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.6.2.tgz#12cfaba693ba20f114ed5765467ff25fdf67ddb0" @@@ -76,9 -87,13 +93,13 @@@ csstype "^2.0.0" indefinite-observable "^1.0.1" + "@types/lodash@4.14.109": + version "4.14.109" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.109.tgz#b1c4442239730bf35cabaf493c772b18c045886d" + -"@types/node@*", "@types/node@10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.1.2.tgz#1b928a0baa408fc8ae3ac012cc81375addc147c6" +"@types/node@*", "@types/node@10.3.0": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.3.0.tgz#078516315a84d56216b5d4fed8f75d59d3b16cac" "@types/react-dom@16.0.5": version "16.0.5"