Merge branch 'master' into 13905-restoring-correct-tree-state-and-panel-item-highligh...
authorPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Fri, 3 Aug 2018 12:41:57 +0000 (14:41 +0200)
committerPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Fri, 3 Aug 2018 12:41:57 +0000 (14:41 +0200)
refs #13905

Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>

src/store/navigation/navigation-action.ts
src/validators/create-collection/create-collection-validator.tsx [new file with mode: 0644]
src/validators/create-project/create-project-validator.tsx
src/views-components/create-project-dialog/create-project-dialog.tsx
src/views-components/dialog-create/dialog-collection-create.tsx
src/views-components/dialog-update/dialog-collection-update.tsx
src/views/workbench/workbench.tsx

index ffb0f7acf6f5fc3e69b1c0295936f6ee8c4eacc5..9f49f25692efbed1479add06149775a43699f47a 100644 (file)
@@ -11,7 +11,11 @@ import { RootState } from "../store";
 import { Resource, ResourceKind } from "../../models/resource";
 import { projectPanelActions } from "../project-panel/project-panel-action";
 import { getCollectionUrl } from "../../models/collection";
-import { getProjectUrl } from "../../models/project";
+import { getProjectUrl, ProjectResource } from "../../models/project";
+import { ProjectService } from "../../services/project-service/project-service";
+import { ServiceRepository } from "../../services/services";
+import { sidePanelActions } from "../side-panel/side-panel-action";
+import { SidePanelIdentifiers } from "../side-panel/side-panel-reducer";
 
 export const getResourceUrl = <T extends Resource>(resource: T): string => {
     switch (resource.kind) {
@@ -28,7 +32,7 @@ export enum ItemMode {
 }
 
 export const setProjectItem = (itemId: string, itemMode: ItemMode) =>
-    (dispatch: Dispatch, getState: () => RootState) => {
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         const { projects, router } = getState();
         const treeItem = findTreeItem(projects.items, itemId);
 
@@ -59,3 +63,33 @@ export const setProjectItem = (itemId: string, itemMode: ItemMode) =>
         }
     };
 
+export const restoreBranch = (itemId: string) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const ancestors = await loadProjectAncestors(itemId, services.projectService);
+        const uuids = ancestors.map(ancestor => ancestor.uuid);
+        await loadBranch(uuids, dispatch);
+        dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(SidePanelIdentifiers.PROJECTS));
+        uuids.forEach(uuid => {
+            dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(uuid));
+        });
+    };
+
+const USER_UUID_REGEX = /.*tpzed.*/;
+
+export const loadProjectAncestors = async (uuid: string, projectService: ProjectService): Promise<Array<ProjectResource>> => {
+    if (USER_UUID_REGEX.test(uuid)) {
+        return [];
+    } else {
+        const currentProject = await projectService.get(uuid);
+        const ancestors = await loadProjectAncestors(currentProject.ownerUuid, projectService);
+        return [...ancestors, currentProject];
+    }
+};
+
+const loadBranch = async (uuids: string[], dispatch: Dispatch): Promise<any> => {
+    const [uuid, ...rest] = uuids;
+    if (uuid) {
+        await dispatch<any>(getProjectList(uuid));
+        return loadBranch(rest, dispatch);
+    }
+};
diff --git a/src/validators/create-collection/create-collection-validator.tsx b/src/validators/create-collection/create-collection-validator.tsx
new file mode 100644 (file)
index 0000000..2d8e1f5
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { require } from '../require';
+import { maxLength } from '../max-length';
+
+export const COLLECTION_NAME_VALIDATION = [require, maxLength(255)];
+export const COLLECTION_DESCRIPTION_VALIDATION = [maxLength(255)];
\ No newline at end of file
index 527043d9d8567024c60546091f6b4103dcdbe684..928efdd2205e439c82fbd936e0e476e13f046139 100644 (file)
@@ -7,5 +7,3 @@ import { maxLength } from '../max-length';
 
 export const PROJECT_NAME_VALIDATION = [require, maxLength(255)];
 export const PROJECT_DESCRIPTION_VALIDATION = [maxLength(255)];
-export const COLLECTION_NAME_VALIDATION = [require, maxLength(255)];
-export const COLLECTION_DESCRIPTION_VALIDATION = [maxLength(255)];
index 1a521890d71be9ac684cb57335dee9d935e29526..aa0dc7bc89a49ea3584806556d268435a05e737d 100644 (file)
@@ -21,7 +21,7 @@ const addProject = (data: { name: string, description: string }) =>
         const { ownerUuid } = getState().projects.creator;
         return dispatch<any>(createProject(data)).then(() => {
             dispatch(snackbarActions.OPEN_SNACKBAR({
-                message: "Created a new project",
+                message: "Project has been successfully created.",
                 hideDuration: 2000
             }));
             dispatch(projectPanelActions.REQUEST_ITEMS());
index 3e3b74aa92747d9adf5053d543097a1110ee3ace..874ce138c76e456ff798e3d63edb88a4d3aa79e2 100644 (file)
@@ -12,7 +12,7 @@ import DialogContent from '@material-ui/core/DialogContent';
 import DialogTitle from '@material-ui/core/DialogTitle';
 import { Button, StyleRulesCallback, WithStyles, withStyles, CircularProgress } from '@material-ui/core';
 
-import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-project/create-project-validator';
+import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-collection/create-collection-validator';
 
 type CssRules = "button" | "lastButton" | "formContainer" | "textField" | "createProgress" | "dialogActions";
 
index 80a82b27fd97bb27a65dd954603e1cb7c2a965d8..08eee418bdc1f2bf016c0e575e0d751b3d96137c 100644 (file)
@@ -7,7 +7,7 @@ import { reduxForm, Field } from 'redux-form';
 import { compose } from 'redux';
 import { ArvadosTheme } from '../../common/custom-theme';
 import { Dialog, DialogActions, DialogContent, DialogTitle, TextField, StyleRulesCallback, withStyles, WithStyles, Button, CircularProgress } from '../../../node_modules/@material-ui/core';
-import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-project/create-project-validator';
+import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-collection/create-collection-validator';
 import { COLLECTION_FORM_NAME } from '../../store/collections/updator/collection-updator-action';
 
 type CssRules = 'content' | 'actions' | 'textField' | 'buttonWrapper' | 'saveButton' | 'circularProgress';
index 3611d7b10fb12210f9573f9ebf2df41476d62693..e78c3e7cddcd1d9f58c29772ab171a3e7bd6378f 100644 (file)
@@ -18,7 +18,7 @@ import { TreeItem } from "../../components/tree/tree";
 import { getTreePath } from '../../store/project/project-reducer';
 import { sidePanelActions } from '../../store/side-panel/side-panel-action';
 import { SidePanel, SidePanelItem } from '../../components/side-panel/side-panel';
-import { ItemMode, setProjectItem } from "../../store/navigation/navigation-action";
+import { ItemMode, setProjectItem, restoreBranch } from "../../store/navigation/navigation-action";
 import { projectActions } from "../../store/project/project-action";
 import { collectionCreateActions } from '../../store/collections/creator/collection-creator-action';
 import { ProjectPanel } from "../project-panel/project-panel";
@@ -93,6 +93,7 @@ interface WorkbenchDataProps {
     user?: User;
     currentToken?: string;
     sidePanelItems: SidePanelItem[];
+    router?: any;
 }
 
 interface WorkbenchServiceProps {
@@ -130,7 +131,8 @@ export const Workbench = withStyles(styles)(
             currentProjectId: state.projects.currentItemId,
             user: state.auth.user,
             currentToken: state.auth.apiToken,
-            sidePanelItems: state.sidePanel
+            sidePanelItems: state.sidePanel,
+            router: state.router.location
         })
     )(
         class extends React.Component<WorkbenchProps, WorkbenchState> {
@@ -170,6 +172,20 @@ export const Workbench = withStyles(styles)(
                 }
             };
 
+            componentDidMount() {
+                const PROJECT_URL_REGEX = /\/projects\/(.*)/;
+                const getProjectIdFromUrl = (url: string) => {
+                    const match = PROJECT_URL_REGEX.exec(url);
+                    return match ? match[1] : match;
+                };
+
+                const id = getProjectIdFromUrl(this.props.router.pathname);
+                if (id) {
+                    this.props.dispatch<any>(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(SidePanelIdentifiers.PROJECTS));
+                    this.props.dispatch<any>(restoreBranch(id));
+                }
+            }
+
             render() {
                 const path = getTreePath(this.props.projects, this.props.currentProjectId);
                 const breadcrumbs = path.map(item => ({
@@ -277,7 +293,7 @@ export const Workbench = withStyles(styles)(
                         case ResourceKind.COLLECTION:
                             this.props.dispatch(loadCollection(item.uuid, item.kind as ResourceKind));
                             this.props.dispatch(push(getCollectionUrl(item.uuid)));
-                        default: 
+                        default:
                             this.props.dispatch(setProjectItem(item.uuid, ItemMode.ACTIVE));
                             this.props.dispatch(loadDetails(item.uuid, item.kind as ResourceKind));
                     }