extend-tree-picker
authorPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Mon, 8 Apr 2019 07:22:02 +0000 (09:22 +0200)
committerPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Mon, 8 Apr 2019 07:22:02 +0000 (09:22 +0200)
Feature #14941

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

src/models/tree.ts
src/store/tree-picker/tree-picker-actions.ts
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
src/views-components/projects-tree-picker/public-favorites-tree-picker.tsx [new file with mode: 0644]

index bec2f758a478335e6ef437afe6592dde144ce729..60a95342eedbbe6b8337f16c84ea896e6f978dcd 100644 (file)
@@ -27,7 +27,8 @@ export enum TreeNodeStatus {
 export enum TreePickerId {
     PROJECTS = 'Projects',
     SHARED_WITH_ME = 'Shared with me',
-    FAVORITES = 'Favorites'
+    FAVORITES = 'Favorites',
+    PUBLIC_FAVORITES = 'Public Favorites'
 }
 
 export const createTree = <T>(): Tree<T> => ({});
index 657d65b75f71aea7217bf488d51a76a85765ec1e..e4d6d9339508893208d43ef784983ccad501c8f0 100644 (file)
@@ -16,6 +16,7 @@ import { ProjectsTreePickerItem } from '~/views-components/projects-tree-picker/
 import { OrderBuilder } from '~/services/api/order-builder';
 import { ProjectResource } from '~/models/project';
 import { mapTree } from '../../models/tree';
+import { LinkResource, LinkClass } from "~/models/link";
 
 export const treePickerActions = unionize({
     LOAD_TREE_PICKER_NODE: ofType<{ id: string, pickerId: string }>(),
@@ -37,6 +38,7 @@ export const getProjectsTreePickerIds = (pickerId: string) => ({
     home: `${pickerId}_home`,
     shared: `${pickerId}_shared`,
     favorites: `${pickerId}_favorites`,
+    publicFavorites: `${pickerId}_publicFavorites`
 });
 
 export const getAllNodes = <Value>(pickerId: string, filter = (node: TreeNode<Value>) => true) => (state: TreePicker) =>
@@ -64,10 +66,11 @@ export const getSelectedNodes = <Value>(pickerId: string) => (state: TreePicker)
 
 export const initProjectsTreePicker = (pickerId: string) =>
     async (dispatch: Dispatch, _: () => RootState, services: ServiceRepository) => {
-        const { home, shared, favorites } = getProjectsTreePickerIds(pickerId);
+        const { home, shared, favorites, publicFavorites } = getProjectsTreePickerIds(pickerId);
         dispatch<any>(initUserProject(home));
         dispatch<any>(initSharedProject(shared));
         dispatch<any>(initFavoritesProject(favorites));
+        dispatch<any>(initPublicFavoritesProject(publicFavorites));
     };
 
 interface ReceiveTreePickerDataParams<T> {
@@ -205,6 +208,21 @@ export const initFavoritesProject = (pickerId: string) =>
         }));
     };
 
+export const PUBLIC_FAVORITES_PROJECT_ID = 'Public Favorites';
+export const initPublicFavoritesProject = (pickerId: string) =>
+    async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(receiveTreePickerData({
+            id: '',
+            pickerId,
+            data: [{ uuid: PUBLIC_FAVORITES_PROJECT_ID, name: PUBLIC_FAVORITES_PROJECT_ID }],
+            extractNodeData: value => ({
+                id: value.uuid,
+                status: TreeNodeStatus.INITIAL,
+                value,
+            }),
+        }));
+    };
+
 interface LoadFavoritesProjectParams {
     pickerId: string;
     includeCollections?: boolean;
@@ -243,6 +261,43 @@ export const loadFavoritesProject = (params: LoadFavoritesProjectParams) =>
         }
     };
 
+export const loadPublicFavoritesProject = (params: LoadFavoritesProjectParams) =>
+    async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        const { pickerId, includeCollections = false, includeFiles = false } = params;
+        const uuidPrefix = getState().config.uuidPrefix;
+        const uuid = `${uuidPrefix}-j7d0g-fffffffffffffff`;
+        if (uuid) {
+
+            const filters = pipe(
+                (fb: FilterBuilder) => includeCollections
+                    ? fb.addIsA('headUuid', [ResourceKind.PROJECT, ResourceKind.COLLECTION])
+                    : fb.addIsA('headUuid', [ResourceKind.PROJECT]),
+                fb => fb
+                    .addEqual('linkClass', LinkClass.STAR)
+                    .addEqual('ownerUuid', uuid)
+                    .addLike('name', '')
+                    .getFilters(),
+            )(new FilterBuilder());
+
+            const { items } = await services.linkService.list({ filters });
+
+            dispatch<any>(receiveTreePickerData<LinkResource>({
+                id: 'Public Favorites',
+                pickerId,
+                data: items,
+                extractNodeData: item => ({
+                    id: item.headUuid,
+                    value: item,
+                    status: item.headKind === ResourceKind.PROJECT
+                        ? TreeNodeStatus.INITIAL
+                        : includeFiles
+                            ? TreeNodeStatus.INITIAL
+                            : TreeNodeStatus.LOADED
+                }),
+            }));
+        }
+    };
+
 export const receiveTreePickerProjectsData = (id: string, projects: ProjectResource[], pickerId: string) =>
     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         dispatch(treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({
@@ -280,6 +335,22 @@ export const loadFavoriteTreePickerProjects = (id: string) =>
 
     };
 
+export const loadPublicFavoriteTreePickerProjects = (id: string) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const parentId = services.authService.getUuid() || '';
+
+        if (id === '') {
+            dispatch(treePickerActions.LOAD_TREE_PICKER_NODE({ id: parentId, pickerId: TreePickerId.PUBLIC_FAVORITES }));
+            const { items } = await services.favoriteService.list(parentId);
+            dispatch<any>(receiveTreePickerProjectsData(parentId, items as ProjectResource[], TreePickerId.PUBLIC_FAVORITES));
+        } else {
+            dispatch(treePickerActions.LOAD_TREE_PICKER_NODE({ id, pickerId: TreePickerId.PUBLIC_FAVORITES }));
+            const { items } = await services.projectService.list(buildParams(id));
+            dispatch<any>(receiveTreePickerProjectsData(id, items, TreePickerId.PUBLIC_FAVORITES));
+        }
+
+    };
+
 const buildParams = (ownerUuid: string) => {
     return {
         filters: new FilterBuilder()
index 2ff9b3c447de8b8e50eb7aeb02c8a180db7cd981..386226510187b66ad1124cf6b2b13d09e9c087e6 100644 (file)
@@ -9,7 +9,7 @@ import { Typography } from "@material-ui/core";
 import { TreePicker, TreePickerProps } from "../tree-picker/tree-picker";
 import { TreeItem, TreeItemStatus } from "~/components/tree/tree";
 import { ProjectResource } from "~/models/project";
-import { treePickerActions, loadProjectTreePickerProjects, loadFavoriteTreePickerProjects } from "~/store/tree-picker/tree-picker-actions";
+import { treePickerActions, loadProjectTreePickerProjects, loadFavoriteTreePickerProjects, loadPublicFavoriteTreePickerProjects } from "~/store/tree-picker/tree-picker-actions";
 import { ListItemTextIcon } from "~/components/list-item-text-icon/list-item-text-icon";
 import { ProjectIcon, FavoriteIcon, ProjectsIcon, ShareMeIcon } from "~/components/icon/icon";
 import { RootState } from "~/store/store";
@@ -46,7 +46,8 @@ const toggleItemOpen = (id: string, status: TreeItemStatus, pickerId: string) =>
                 dispatch<any>(loadProjectTreePickerProjects(id));
             } else if (pickerId === TreePickerId.FAVORITES) {
                 dispatch<any>(loadFavoriteTreePickerProjects(id === services.authService.getUuid() ? '' : id));
-            } else {
+            } else if (pickerId === TreePickerId.PUBLIC_FAVORITES) {
+                dispatch<any>(loadPublicFavoriteTreePickerProjects(id === services.authService.getUuid() ? '' : id));
                 // TODO: load sharedWithMe
             }
         } else {
@@ -67,6 +68,7 @@ export const ProjectTreePicker = connect(undefined, mapDispatchToProps)((props:
             <TreePicker {...props} render={renderTreeItem} pickerId={TreePickerId.PROJECTS} />
             <TreePicker {...props} render={renderTreeItem} pickerId={TreePickerId.SHARED_WITH_ME} />
             <TreePicker {...props} render={renderTreeItem} pickerId={TreePickerId.FAVORITES} />
+            <TreePicker {...props} render={renderTreeItem} pickerId={TreePickerId.PUBLIC_FAVORITES} />
         </div>
     </div>);
 
@@ -78,6 +80,8 @@ const getProjectPickerIcon = (item: TreeItem<ProjectResource>) => {
             return ProjectsIcon;
         case TreePickerId.SHARED_WITH_ME:
             return ShareMeIcon;
+        case TreePickerId.PUBLIC_FAVORITES:
+            return ShareMeIcon;
         default:
             return ProjectIcon;
     }
index fafb05056ca712b86b841bb221da6258129ae080..8e27d445d1a70faa090900975ea8926659dceaea 100644 (file)
@@ -16,13 +16,14 @@ import { GroupContentsResource } from '~/services/groups-service/groups-service'
 import { CollectionDirectory, CollectionFile, CollectionFileType } from '~/models/collection-file';
 import { ResourceKind } from '~/models/resource';
 import { TreePickerProps, TreePicker } from "~/views-components/tree-picker/tree-picker";
+import { LinkResource } from "~/models/link";
 
 export interface ProjectsTreePickerRootItem {
     id: string;
     name: string;
 }
 
-export type ProjectsTreePickerItem = ProjectsTreePickerRootItem | GroupContentsResource | CollectionDirectory | CollectionFile;
+export type ProjectsTreePickerItem = ProjectsTreePickerRootItem | GroupContentsResource | CollectionDirectory | CollectionFile | LinkResource;
 type PickedTreePickerProps = Pick<TreePickerProps<ProjectsTreePickerItem>, 'onContextMenu' | 'toggleItemActive' | 'toggleItemOpen' | 'toggleItemSelection'>;
 
 export interface ProjectsTreePickerDataProps {
@@ -45,9 +46,9 @@ 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))){
+        if (disableActivation.some(isEqual(item.id))) {
             return;
         }
 
@@ -83,6 +84,14 @@ const mapDispatchToProps = (dispatch: Dispatch, { loadRootItem, includeCollectio
 export const ProjectsTreePicker = connect(mapStateToProps, mapDispatchToProps)(TreePicker);
 
 const getProjectPickerIcon = ({ data }: TreeItem<ProjectsTreePickerItem>, rootIcon: IconType): IconType => {
+    if ('headKind' in data) {
+        switch (data.headKind) {
+            case ResourceKind.COLLECTION:
+                return CollectionIcon;
+            default:
+                return ProjectIcon;
+        }
+    }
     if ('kind' in data) {
         switch (data.kind) {
             case ResourceKind.COLLECTION:
index ae98cf00896a3978c137a5593fdadc977c7978e0..653ae604e524574a30009c47c6cb944003d347e9 100644 (file)
@@ -10,6 +10,7 @@ import { FavoritesTreePicker } from '~/views-components/projects-tree-picker/fav
 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';
+import { PublicFavoritesTreePicker } from './public-favorites-tree-picker';
 
 export interface ProjectsTreePickerProps {
     pickerId: string;
@@ -21,7 +22,7 @@ export interface ProjectsTreePickerProps {
 }
 
 export const ProjectsTreePicker = ({ pickerId, ...props }: ProjectsTreePickerProps) => {
-    const { home, shared, favorites } = getProjectsTreePickerIds(pickerId);
+    const { home, shared, favorites, publicFavorites } = getProjectsTreePickerIds(pickerId);
     const relatedTreePickers = getRelatedTreePickers(pickerId);
     const p = {
         ...props,
@@ -32,6 +33,7 @@ export const ProjectsTreePicker = ({ pickerId, ...props }: ProjectsTreePickerPro
         <HomeTreePicker pickerId={home} {...p} />
         <SharedTreePicker pickerId={shared} {...p} />
         <FavoritesTreePicker pickerId={favorites} {...p} />
+        <PublicFavoritesTreePicker pickerId={publicFavorites} {...p} />
     </div>;
 };
 
diff --git a/src/views-components/projects-tree-picker/public-favorites-tree-picker.tsx b/src/views-components/projects-tree-picker/public-favorites-tree-picker.tsx
new file mode 100644 (file)
index 0000000..2d1f975
--- /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/generic-projects-tree-picker';
+import { Dispatch } from 'redux';
+import { FavoriteIcon } from '~/components/icon/icon';
+import { loadPublicFavoritesProject } from '~/store/tree-picker/tree-picker-actions';
+
+export const PublicFavoritesTreePicker = connect(() => ({
+    rootItemIcon: FavoriteIcon,
+}), (dispatch: Dispatch): Pick<ProjectsTreePickerProps, 'loadRootItem'> => ({
+    loadRootItem: (_, pickerId, includeCollections, includeFiles) => {
+        dispatch<any>(loadPublicFavoritesProject({ pickerId, includeCollections, includeFiles }));
+    },
+}))(ProjectsTreePicker);
\ No newline at end of file