Create favorites tree picker
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Tue, 9 Oct 2018 12:25:55 +0000 (14:25 +0200)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Tue, 9 Oct 2018 12:25:55 +0000 (14:25 +0200)
Feature #13862

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

src/index.tsx
src/store/tree-picker/tree-picker-actions.ts
src/views-components/projects-tree-picker/favorites-tree-picker.tsx [new file with mode: 0644]
src/views-components/tree-picker/tree-picker.ts
src/views/workbench/workbench.tsx

index 444a3ec0a397b71f5097509cc1b0b981c7f46fb1..16cf86a36815874900ea5b109aaebf55b73c07c4 100644 (file)
@@ -43,7 +43,7 @@ import { trashedCollectionActionSet } from '~/views-components/context-menu/acti
 import { ContainerRequestState } from '~/models/container-request';
 import { MountKind } from '~/models/mount-types';
 import { receiveTreePickerData, loadUserProject } from '~/store/tree-picker/tree-picker-actions';
-import { loadProject, loadCollection, initUserProject, initSharedProject } from './store/tree-picker/tree-picker-actions';
+import { loadProject, loadCollection, initUserProject, initSharedProject, initFavoritesProject } from './store/tree-picker/tree-picker-actions';
 import { ResourceKind } from '~/models/resource';
 
 const getBuildNumber = () => "BN-" + (process.env.REACT_APP_BUILD_NUMBER || "dev");
@@ -123,6 +123,9 @@ const initListener = (history: History, store: RootStore, services: ServiceRepos
             store.dispatch(initSharedProject('testPicker4'));
             store.dispatch(initSharedProject('testPicker5'));
             store.dispatch(initSharedProject('testPicker6'));
+            store.dispatch(initFavoritesProject('testPicker7'));
+            store.dispatch(initFavoritesProject('testPicker8'));
+            store.dispatch(initFavoritesProject('testPicker9'));
             // await store.dispatch(loadCollection(
             //     'c97qk-4zz18-9sn8ygaf62chkkd',
             //     'testPicker',
index a4da9d46c4ba88d4454164bad84a9c500abaa756..41ee62f8e1910e5fb1c274711c8138bda4489d8d 100644 (file)
@@ -120,7 +120,7 @@ export const loadUserProject = (pickerId: string, includeCollections = false, in
     async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
         const uuid = services.authService.getUuid();
         if (uuid) {
-            dispatch(loadProject({id: uuid, pickerId, includeCollections, includeFiles}));
+            dispatch(loadProject({ id: uuid, pickerId, includeCollections, includeFiles }));
         }
     };
 
@@ -138,3 +138,54 @@ export const initSharedProject = (pickerId: string) =>
             }),
         }));
     };
+
+export const initFavoritesProject = (pickerId: string) =>
+    async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(receiveTreePickerData({
+            id: '',
+            pickerId,
+            data: [{ uuid: 'Favorites', name: 'Favorites' }],
+            extractNodeData: value => ({
+                id: value.uuid,
+                status: TreeNodeStatus.INITIAL,
+                value,
+            }),
+        }));
+    };
+
+interface LoadFavoritesProjectParams {
+    pickerId: string;
+    includeCollections?: boolean;
+    includeFiles?: boolean;
+}
+export const loadFavoritesProject = (params: LoadFavoritesProjectParams) =>
+    async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        const { pickerId, includeCollections = false, includeFiles = false } = params;
+        const uuid = services.authService.getUuid();
+        if (uuid) {
+
+            const filters = pipe(
+                (fb: FilterBuilder) => includeCollections
+                    ? fb.addIsA('headUuid', [ResourceKind.PROJECT, ResourceKind.COLLECTION])
+                    : fb.addIsA('headUuid', [ResourceKind.PROJECT]),
+                fb => fb.getFilters(),
+            )(new FilterBuilder());
+
+            const { items } = await services.favoriteService.list(uuid, { filters });
+
+            dispatch<any>(receiveTreePickerData<GroupContentsResource>({
+                id: 'Favorites',
+                pickerId,
+                data: items,
+                extractNodeData: item => ({
+                    id: item.uuid,
+                    value: item,
+                    status: item.kind === ResourceKind.PROJECT
+                        ? TreeNodeStatus.INITIAL
+                        : includeFiles
+                            ? TreeNodeStatus.INITIAL
+                            : TreeNodeStatus.LOADED
+                }),
+            }));
+        }
+    };
diff --git a/src/views-components/projects-tree-picker/favorites-tree-picker.tsx b/src/views-components/projects-tree-picker/favorites-tree-picker.tsx
new file mode 100644 (file)
index 0000000..74cb16a
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { connect } from 'react-redux';
+import { ProjectsTreePicker, ProjectsTreePickerProps } from '~/views-components/projects-tree-picker/projects-tree-picker';
+import { Dispatch } from 'redux';
+import { FavoriteIcon } from '~/components/icon/icon';
+import { loadFavoritesProject } from '~/store/tree-picker/tree-picker-actions';
+
+export const FavoritesProjectsTreePicker = connect(() => ({
+    rootItemIcon: FavoriteIcon,
+}), (dispatch: Dispatch): Pick<ProjectsTreePickerProps, 'loadRootItem'> => ({
+    loadRootItem: (_, pickerId, includeCollections, includeFiles) => {
+        dispatch<any>(loadFavoritesProject({ pickerId, includeCollections, includeFiles }));
+    },
+}))(ProjectsTreePicker);
\ No newline at end of file
index 2e1d98ea8725e838aeb0f65b39bac450532d826c..cb829059a5889f5e2872b9a95b602fa03c429cf9 100644 (file)
@@ -20,12 +20,13 @@ export interface TreePickerProps<T> {
 
 const memoizedMapStateToProps = () => {
     let prevTree: Ttree<any>;
-    let mappedProps: Pick<TreeProps<any>, 'items'>;
-    return <T>(state: RootState, props: TreePickerProps<T>): Pick<TreeProps<T>, 'items'> => {
+    let mappedProps: Pick<TreeProps<any>, 'items' | 'disableRipple'>;
+    return <T>(state: RootState, props: TreePickerProps<T>): Pick<TreeProps<T>, 'items' | 'disableRipple'> => {
         const tree = state.treePicker[props.pickerId] || createTree();
         if (tree !== prevTree) {
             prevTree = tree;
             mappedProps = {
+                disableRipple: true,
                 items: getNodeChildrenIds('')(tree)
                     .map(treePickerToTreeItems(tree))
             };
index 96f54730062573e00ac6da30e9d672f492f79798..6c02dd272b98ed422da91574124296496fb996a8 100644 (file)
@@ -48,6 +48,7 @@ import { GroupContentsResource } from '~/services/groups-service/groups-service'
 import { ProjectsTreePicker } from '~/views-components/projects-tree-picker/projects-tree-picker';
 import { UserProjectsTreePicker } from '~/views-components/projects-tree-picker/user-projects-tree-picker';
 import { SharedProjectsTreePicker } from '~/views-components/projects-tree-picker/shared-projects-tree-picker';
+import { FavoritesProjectsTreePicker } from '../../views-components/projects-tree-picker/favorites-tree-picker';
 
 type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
 
@@ -101,6 +102,9 @@ export const WorkbenchPanel =
                             <SharedProjectsTreePicker pickerId='testPicker4'/>
                             <SharedProjectsTreePicker pickerId='testPicker5' includeCollections/>
                             <SharedProjectsTreePicker pickerId='testPicker6' includeCollections includeFiles/>
+                            <FavoritesProjectsTreePicker pickerId='testPicker7'/>
+                            <FavoritesProjectsTreePicker pickerId='testPicker8' includeCollections/>
+                            <FavoritesProjectsTreePicker pickerId='testPicker9' includeCollections includeFiles/>
                             <Switch>
                                 <Route path={Routes.PROJECTS} component={ProjectPanel} />
                                 <Route path={Routes.COLLECTIONS} component={CollectionPanel} />