Merge branch '14470-update-tree-pickers-to-handle-shared-items' into 14470-replace...
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Thu, 15 Nov 2018 13:56:56 +0000 (14:56 +0100)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Thu, 15 Nov 2018 13:56:56 +0000 (14:56 +0100)
refs #14470
14470

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

12 files changed:
src/store/collections/collection-move-actions.ts
src/store/processes/process-move-actions.ts
src/store/projects/project-move-actions.ts
src/store/tree-picker/picker-id.tsx [new file with mode: 0644]
src/store/tree-picker/tree-picker-actions.ts
src/views-components/dialog-forms/move-collection-dialog.ts
src/views-components/dialog-forms/move-process-dialog.ts
src/views-components/dialog-forms/move-project-dialog.ts
src/views-components/dialog-move/dialog-move-to.tsx
src/views-components/project-tree-picker/project-tree-picker.tsx
src/views-components/projects-tree-picker/generic-projects-tree-picker.tsx
src/views-components/projects-tree-picker/projects-tree-picker.tsx

index 54508e139f2b2b35bdfb14fb0bdfe805c1c3847e..8be625099fecccf1e40066106c04b70c44c70031 100644 (file)
@@ -13,12 +13,14 @@ import { projectPanelActions } from '~/store/project-panel/project-panel-action'
 import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
 import { resetPickerProjectTree } from '~/store/project-tree-picker/project-tree-picker-actions';
 import { progressIndicatorActions } from "~/store/progress-indicator/progress-indicator-actions";
+import { initProjectsTreePicker } from '../tree-picker/tree-picker-actions';
 
 export const COLLECTION_MOVE_FORM_NAME = 'collectionMoveFormName';
 
 export const openMoveCollectionDialog = (resource: { name: string, uuid: string }) =>
     (dispatch: Dispatch) => {
         dispatch<any>(resetPickerProjectTree());
+        dispatch<any>(initProjectsTreePicker(COLLECTION_MOVE_FORM_NAME));
         dispatch(initialize(COLLECTION_MOVE_FORM_NAME, resource));
         dispatch(dialogActions.OPEN_DIALOG({ id: COLLECTION_MOVE_FORM_NAME, data: {} }));
     };
index 6df826992861cc965abef5c430bd780a22d11164..edba5a8574e16814c6a23988d85a1d4657d431b5 100644 (file)
@@ -13,6 +13,7 @@ import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
 import { resetPickerProjectTree } from '~/store/project-tree-picker/project-tree-picker-actions';
 import { projectPanelActions } from '~/store/project-panel/project-panel-action';
 import { getProcess, getProcessStatus, ProcessStatus } from '~/store/processes/process';
+import { initProjectsTreePicker } from '~/store/tree-picker/tree-picker-actions';
 
 export const PROCESS_MOVE_FORM_NAME = 'processMoveFormName';
 
@@ -23,6 +24,7 @@ export const openMoveProcessDialog = (resource: { name: string, uuid: string })
             const processStatus = getProcessStatus(process);
             if (processStatus === ProcessStatus.DRAFT) {
                 dispatch<any>(resetPickerProjectTree());
+                dispatch<any>(initProjectsTreePicker(PROCESS_MOVE_FORM_NAME));
                 dispatch(initialize(PROCESS_MOVE_FORM_NAME, resource));
                 dispatch(dialogActions.OPEN_DIALOG({ id: PROCESS_MOVE_FORM_NAME, data: {} }));
             } else {
index c251bdf8f8724d3a6fd7969dce4aae0b011d1ab2..9405597b2f2846f912d2a5fc5c235af11d517779 100644 (file)
@@ -10,12 +10,14 @@ import { RootState } from '~/store/store';
 import { getCommonResourceServiceError, CommonResourceServiceError } from "~/services/common-service/common-resource-service";
 import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
 import { resetPickerProjectTree } from '~/store/project-tree-picker/project-tree-picker-actions';
+import { initProjectsTreePicker } from '../tree-picker/tree-picker-actions';
 
 export const PROJECT_MOVE_FORM_NAME = 'projectMoveFormName';
 
 export const openMoveProjectDialog = (resource: { name: string, uuid: string }) =>
     (dispatch: Dispatch) => {
         dispatch<any>(resetPickerProjectTree());
+        dispatch<any>(initProjectsTreePicker(PROJECT_MOVE_FORM_NAME));
         dispatch(initialize(PROJECT_MOVE_FORM_NAME, resource));
         dispatch(dialogActions.OPEN_DIALOG({ id: PROJECT_MOVE_FORM_NAME, data: {} }));
     };
diff --git a/src/store/tree-picker/picker-id.tsx b/src/store/tree-picker/picker-id.tsx
new file mode 100644 (file)
index 0000000..5621954
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+
+export const pickerId =
+    (id: string) =>
+        <P extends { pickerId: string }>(Component: React.ComponentType<P>) =>
+            (props: P) =>
+                <Component {...props} pickerId={id} />;
+                
\ No newline at end of file
index a3816354828d2478d7125d001e699165d0005e36..657d65b75f71aea7217bf488d51a76a85765ec1e 100644 (file)
@@ -137,7 +137,7 @@ export const loadCollection = (id: string, pickerId: string) =>
             if (node && 'kind' in node.value && node.value.kind === ResourceKind.COLLECTION) {
 
                 const filesTree = await services.collectionService.files(node.value.portableDataHash);
-                
+
                 dispatch(
                     treePickerActions.APPEND_TREE_PICKER_NODE_SUBTREE({
                         id,
@@ -175,13 +175,13 @@ export const loadUserProject = (pickerId: string, includeCollections = false, in
         }
     };
 
-
+export const SHARED_PROJECT_ID = 'Shared with me';
 export const initSharedProject = (pickerId: string) =>
     async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
         dispatch(receiveTreePickerData({
             id: '',
             pickerId,
-            data: [{ uuid: 'Shared with me', name: 'Shared with me' }],
+            data: [{ uuid: SHARED_PROJECT_ID, name: SHARED_PROJECT_ID }],
             extractNodeData: value => ({
                 id: value.uuid,
                 status: TreeNodeStatus.INITIAL,
@@ -190,12 +190,13 @@ export const initSharedProject = (pickerId: string) =>
         }));
     };
 
+export const FAVORITES_PROJECT_ID = 'Favorites';
 export const initFavoritesProject = (pickerId: string) =>
     async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
         dispatch(receiveTreePickerData({
             id: '',
             pickerId,
-            data: [{ uuid: 'Favorites', name: 'Favorites' }],
+            data: [{ uuid: FAVORITES_PROJECT_ID, name: FAVORITES_PROJECT_ID }],
             extractNodeData: value => ({
                 id: value.uuid,
                 status: TreeNodeStatus.INITIAL,
index fcdd999393ba7e765ad283110dd3a5ab1b7b7be3..b817b6a0fe435c80f510a7bc61eaa2063c3d3ea8 100644 (file)
@@ -9,6 +9,7 @@ import { DialogMoveTo } from '~/views-components/dialog-move/dialog-move-to';
 import { COLLECTION_MOVE_FORM_NAME } from '~/store/collections/collection-move-actions';
 import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
 import { moveCollection } from '~/store/workbench/workbench-actions';
+import { pickerId } from '~/store/tree-picker/picker-id';
 
 export const MoveCollectionDialog = compose(
     withDialog(COLLECTION_MOVE_FORM_NAME),
@@ -17,5 +18,6 @@ export const MoveCollectionDialog = compose(
         onSubmit: (data, dispatch) => {
             dispatch(moveCollection(data));
         }
-    })
+    }),
+    pickerId(COLLECTION_MOVE_FORM_NAME),
 )(DialogMoveTo);
index baea34bc71c63ba2a1c7634a34101f0974f0d669..ce854ef251a04eb0e49b7a65a54f8f1ea4f3cfc2 100644 (file)
@@ -9,6 +9,7 @@ import { PROCESS_MOVE_FORM_NAME } from '~/store/processes/process-move-actions';
 import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
 import { DialogMoveTo } from '~/views-components/dialog-move/dialog-move-to';
 import { moveProcess } from '~/store/workbench/workbench-actions';
+import { pickerId } from '~/store/tree-picker/picker-id';
 
 export const MoveProcessDialog = compose(
     withDialog(PROCESS_MOVE_FORM_NAME),
@@ -17,5 +18,6 @@ export const MoveProcessDialog = compose(
         onSubmit: (data, dispatch) => {
             dispatch(moveProcess(data));
         }
-    })
+    }),
+    pickerId(PROCESS_MOVE_FORM_NAME),
 )(DialogMoveTo);
\ No newline at end of file
index c1fbb76ebc5e973d70962ecea56c6f1359aaffa1..03e474b1778074668cfedcc41a44c4f3e9335d09 100644 (file)
@@ -9,6 +9,7 @@ import { PROJECT_MOVE_FORM_NAME } from '~/store/projects/project-move-actions';
 import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
 import { DialogMoveTo } from '~/views-components/dialog-move/dialog-move-to';
 import { moveProject } from '~/store/workbench/workbench-actions';
+import { pickerId } from '~/store/tree-picker/picker-id';
 
 export const MoveProjectDialog = compose(
     withDialog(PROJECT_MOVE_FORM_NAME),
@@ -17,6 +18,7 @@ export const MoveProjectDialog = compose(
         onSubmit: (data, dispatch) => {
             dispatch(moveProject(data));
         }
-    })
+    }),
+    pickerId(PROJECT_MOVE_FORM_NAME),
 )(DialogMoveTo);
 
index 425b9e462a5439b47f3eb82a26fbe4eefe5481e0..129c59ff33c692b23cbc772fc3a5c58eed0c80ba 100644 (file)
@@ -3,6 +3,7 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from "react";
+import { memoize } from 'lodash/fp';
 import { InjectedFormProps, Field } from 'redux-form';
 import { WithDialogProps } from '~/store/dialog/with-dialog';
 import { FormDialog } from '~/components/form-dialog/form-dialog';
@@ -10,17 +11,19 @@ import { ProjectTreePickerField } from '~/views-components/project-tree-picker/p
 import { MOVE_TO_VALIDATION } from '~/validators/validators';
 import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
 
-export const DialogMoveTo = (props: WithDialogProps<string> & InjectedFormProps<MoveToFormDialogData>) =>
+export const DialogMoveTo = (props: WithDialogProps<string> & InjectedFormProps<MoveToFormDialogData> & { pickerId: string }) =>
     <FormDialog
         dialogTitle='Move to'
-        formFields={MoveToDialogFields}
+        formFields={MoveToDialogFields(props.pickerId)}
         submitLabel='Move'
         {...props}
     />;
 
-const MoveToDialogFields = () =>
-    <Field
-        name="ownerUuid"
-        component={ProjectTreePickerField}
-        validate={MOVE_TO_VALIDATION} />;
+const MoveToDialogFields = memoize(
+    (pickerId: string) => () =>
+        <Field
+            name="ownerUuid"
+            pickerId={pickerId}
+            component={ProjectTreePickerField}
+            validate={MOVE_TO_VALIDATION} />);
 
index a4e4c4062631e6881de807a19970ec9e8b6bd582..101fca08d1b87a652587f97463c82c6b772e0f98 100644 (file)
@@ -16,6 +16,8 @@ import { RootState } from "~/store/store";
 import { ServiceRepository } from "~/services/services";
 import { WrappedFieldProps } from 'redux-form';
 import { TreePickerId } from '~/models/tree';
+import { ProjectsTreePicker } from '~/views-components/projects-tree-picker/projects-tree-picker';
+import { ProjectsTreePickerItem } from '~/views-components/projects-tree-picker/generic-projects-tree-picker';
 
 type ProjectTreePickerProps = Pick<TreePickerProps<ProjectResource>, 'onContextMenu' | 'toggleItemActive' | 'toggleItemOpen' | 'toggleItemSelection'>;
 
@@ -87,17 +89,19 @@ const renderTreeItem = (item: TreeItem<ProjectResource>) =>
         isActive={item.active}
         hasMargin={true} />;
 
-export const ProjectTreePickerField = (props: WrappedFieldProps) =>
+export const ProjectTreePickerField = (props: WrappedFieldProps & { pickerId: string }) =>
     <div style={{ height: '200px', display: 'flex', flexDirection: 'column' }}>
-        <ProjectTreePicker onChange={handleChange(props)} />
+        <ProjectsTreePicker
+            pickerId={props.pickerId}
+            toggleItemActive={handleChange(props)} />
         {props.meta.dirty && props.meta.error &&
             <Typography variant='caption' color='error'>
                 {props.meta.error}
             </Typography>}
     </div>;
 
-const handleChange = (props: WrappedFieldProps) => (value: string) =>
-    props.input.value === value
-        ? props.input.onChange('')
-        : props.input.onChange(value);
-
+const handleChange = (props: WrappedFieldProps) =>
+    (_: any, { id }: TreeItem<ProjectsTreePickerItem>) =>
+        props.input.value === id
+            ? props.input.onChange('')
+            : props.input.onChange(id);
index d8a5d49f0584346146d1f33b70e9aed6440de208..fafb05056ca712b86b841bb221da6258129ae080 100644 (file)
@@ -5,6 +5,7 @@
 import * as React from "react";
 import { Dispatch } from "redux";
 import { connect } from "react-redux";
+import { isEqual } from 'lodash/fp';
 import { TreeItem, TreeItemStatus } from '~/components/tree/tree';
 import { ProjectResource } from "~/models/project";
 import { treePickerActions } from "~/store/tree-picker/tree-picker-actions";
@@ -30,6 +31,7 @@ export interface ProjectsTreePickerDataProps {
     rootItemIcon: IconType;
     showSelection?: boolean;
     relatedTreePickers?: string[];
+    disableActivation?: string[];
     loadRootItem: (item: TreeItem<ProjectsTreePickerRootItem>, pickerId: string, includeCollections?: boolean, inlcudeFiles?: boolean) => void;
 }
 
@@ -43,6 +45,12 @@ const mapStateToProps = (_: any, { rootItemIcon, showSelection }: ProjectsTreePi
 const mapDispatchToProps = (dispatch: Dispatch, { loadRootItem, includeCollections, includeFiles, relatedTreePickers, ...props }: ProjectsTreePickerProps): PickedTreePickerProps => ({
     onContextMenu: () => { return; },
     toggleItemActive: (event, item, pickerId) => {
+        
+        const { disableActivation = [] } = props;
+        if(disableActivation.some(isEqual(item.id))){
+            return;
+        }
+
         dispatch(treePickerActions.ACTIVATE_TREE_PICKER_NODE({ id: item.id, pickerId, relatedTreePickers }));
         if (props.toggleItemActive) {
             props.toggleItemActive(event, item, pickerId);
index 6c66d1a9f1d9ff91fb4ea7bbd4cc5d82d7ed0b75..ae98cf00896a3978c137a5593fdadc977c7978e0 100644 (file)
@@ -3,11 +3,11 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from 'react';
-import { values, memoize, pipe } from 'lodash/fp';
+import { values, memoize, pipe, pick } from 'lodash/fp';
 import { HomeTreePicker } from '~/views-components/projects-tree-picker/home-tree-picker';
 import { SharedTreePicker } from '~/views-components/projects-tree-picker/shared-tree-picker';
 import { FavoritesTreePicker } from '~/views-components/projects-tree-picker/favorites-tree-picker';
-import { getProjectsTreePickerIds } from '~/store/tree-picker/tree-picker-actions';
+import { getProjectsTreePickerIds, SHARED_PROJECT_ID, FAVORITES_PROJECT_ID } from '~/store/tree-picker/tree-picker-actions';
 import { TreeItem } from '~/components/tree/tree';
 import { ProjectsTreePickerItem } from './generic-projects-tree-picker';
 
@@ -23,11 +23,17 @@ export interface ProjectsTreePickerProps {
 export const ProjectsTreePicker = ({ pickerId, ...props }: ProjectsTreePickerProps) => {
     const { home, shared, favorites } = getProjectsTreePickerIds(pickerId);
     const relatedTreePickers = getRelatedTreePickers(pickerId);
+    const p = {
+        ...props,
+        relatedTreePickers,
+        disableActivation
+    };
     return <div>
-        <HomeTreePicker pickerId={home} {...props} {...{ relatedTreePickers }} />
-        <SharedTreePicker pickerId={shared} {...props} {...{ relatedTreePickers }} />
-        <FavoritesTreePicker pickerId={favorites} {...props} {...{ relatedTreePickers }} />
+        <HomeTreePicker pickerId={home} {...p} />
+        <SharedTreePicker pickerId={shared} {...p} />
+        <FavoritesTreePicker pickerId={favorites} {...p} />
     </div>;
 };
 
 const getRelatedTreePickers = memoize(pipe(getProjectsTreePickerIds, values));
+const disableActivation = [SHARED_PROJECT_ID, FAVORITES_PROJECT_ID];