[arvados-workbench2] created: 2.4.0-350-g0ba78ca9

git repository hosting git at public.arvados.org
Tue Nov 15 14:47:59 UTC 2022


        at  0ba78ca92c70bf7196ed400a655aa2d625fe8475 (commit)


commit 0ba78ca92c70bf7196ed400a655aa2d625fe8475
Author: Stephen Smith <stephen at curii.com>
Date:   Tue Nov 15 09:43:01 2022 -0500

    19504: Add process / output collection parent process & resource icons to breadcrumbs
    
    Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen at curii.com>

diff --git a/src/components/breadcrumbs/breadcrumbs.tsx b/src/components/breadcrumbs/breadcrumbs.tsx
index 71796661..0348b814 100644
--- a/src/components/breadcrumbs/breadcrumbs.tsx
+++ b/src/components/breadcrumbs/breadcrumbs.tsx
@@ -9,12 +9,12 @@ import { withStyles } from '@material-ui/core';
 import { IllegalNamingWarning } from '../warning/warning';
 import { IconType, FreezeIcon } from 'components/icon/icon';
 import grey from '@material-ui/core/colors/grey';
-import { ResourceBreadcrumb } from 'store/breadcrumbs/breadcrumbs-actions';
 import { ResourcesState } from 'store/resources/resources';
 
 export interface Breadcrumb {
     label: string;
     icon?: IconType;
+    uuid: string;
 }
 
 type CssRules = "item" | "currentItem" | "label" | "icon" | "frozenIcon";
@@ -42,10 +42,10 @@ const styles: StyleRulesCallback<CssRules> = theme => ({
 });
 
 export interface BreadcrumbsProps {
-    items: ResourceBreadcrumb[];
+    items: Breadcrumb[];
     resources: ResourcesState;
-    onClick: (breadcrumb: ResourceBreadcrumb) => void;
-    onContextMenu: (event: React.MouseEvent<HTMLElement>, breadcrumb: ResourceBreadcrumb) => void;
+    onClick: (breadcrumb: Breadcrumb) => void;
+    onContextMenu: (event: React.MouseEvent<HTMLElement>, breadcrumb: Breadcrumb) => void;
 }
 
 export const Breadcrumbs = withStyles(styles)(
diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx
index a6c118fc..7fd32e54 100644
--- a/src/components/icon/icon.tsx
+++ b/src/components/icon/icon.tsx
@@ -56,6 +56,7 @@ import RestoreFromTrash from '@material-ui/icons/History';
 import Search from '@material-ui/icons/Search';
 import SettingsApplications from '@material-ui/icons/SettingsApplications';
 import SettingsEthernet from '@material-ui/icons/SettingsEthernet';
+import Settings from '@material-ui/icons/Settings';
 import Star from '@material-ui/icons/Star';
 import StarBorder from '@material-ui/icons/StarBorder';
 import Warning from '@material-ui/icons/Warning';
@@ -216,3 +217,4 @@ export const ActiveIcon: IconType = (props) => <CheckCircleOutline {...props} />
 export const SetupIcon: IconType = (props) => <RemoveCircleOutline {...props} />;
 export const InactiveIcon: IconType = (props) => <NotInterested {...props} />;
 export const ImageIcon: IconType = (props) => <Image {...props} />;
+export const ProcessBreadcrumbIcon: IconType = (props) => <Settings {...props} />;
diff --git a/src/store/breadcrumbs/breadcrumbs-actions.ts b/src/store/breadcrumbs/breadcrumbs-actions.ts
index 08e1a132..65b2870b 100644
--- a/src/store/breadcrumbs/breadcrumbs-actions.ts
+++ b/src/store/breadcrumbs/breadcrumbs-actions.ts
@@ -5,7 +5,6 @@
 import { Dispatch } from 'redux';
 import { RootState } from 'store/store';
 import { getUserUuid } from "common/getuser";
-import { Breadcrumb } from 'components/breadcrumbs/breadcrumbs';
 import { getResource } from 'store/resources/resources';
 import { TreePicker } from '../tree-picker/tree-picker';
 import { getSidePanelTreeBranch, getSidePanelTreeNodeAncestorsIds } from '../side-panel-tree/side-panel-tree-actions';
@@ -18,28 +17,56 @@ import { ResourceKind } from 'models/resource';
 import { GroupResource } from 'models/group';
 import { extractUuidKind } from 'models/resource';
 import { UserResource } from 'models/user';
+import { containerRequestFieldsNoMounts } from 'store/all-processes-panel/all-processes-panel-middleware-service';
+import { FilterBuilder } from 'services/api/filter-builder';
+import { ProcessResource } from 'models/process';
+import { OrderBuilder } from 'services/api/order-builder';
+import { Breadcrumb } from 'components/breadcrumbs/breadcrumbs';
+import { ContainerRequestResource } from 'models/container-request';
+import { CollectionIcon, IconType, ProcessBreadcrumbIcon, ProjectIcon } from 'components/icon/icon';
+import { CollectionResource } from 'models/collection';
 
 export const BREADCRUMBS = 'breadcrumbs';
 
-export interface ResourceBreadcrumb extends Breadcrumb {
-    uuid: string;
-}
-
-export const setBreadcrumbs = (breadcrumbs: any, currentItem?: any) => {
+export const setBreadcrumbs = (breadcrumbs: any, currentItem?: CollectionResource | ContainerRequestResource | GroupResource) => {
     if (currentItem) {
-        const addLastItem = { label: currentItem.name, uuid: currentItem.uuid };
-        breadcrumbs.push(addLastItem);
+        breadcrumbs.push(resourceToBreadcrumb(currentItem));
     }
     return propertiesActions.SET_PROPERTY({ key: BREADCRUMBS, value: breadcrumbs });
 };
 
+const resourceToBreadcrumbIcon = (resource: CollectionResource | ContainerRequestResource | GroupResource): IconType | undefined => {
+    switch (resource.kind) {
+        case ResourceKind.PROJECT:
+            return ProjectIcon;
+            break;
+
+        case ResourceKind.PROCESS:
+            return ProcessBreadcrumbIcon;
+            break;
+
+        case ResourceKind.COLLECTION:
+            return CollectionIcon;
+            break;
+
+        default:
+            return undefined;
+            break;
+    }
+}
+
+const resourceToBreadcrumb = (resource: CollectionResource | ContainerRequestResource | GroupResource) => ({
+    label: resource.name,
+    uuid: resource.uuid,
+    icon: resourceToBreadcrumbIcon(resource),
+})
 
-const getSidePanelTreeBreadcrumbs = (uuid: string) => (treePicker: TreePicker): ResourceBreadcrumb[] => {
+const getSidePanelTreeBreadcrumbs = (uuid: string) => (treePicker: TreePicker): Breadcrumb[] => {
     const nodes = getSidePanelTreeBranch(uuid)(treePicker);
     return nodes.map(node =>
         typeof node.value === 'string'
             ? { label: node.value, uuid: node.id }
-            : { label: node.value.name, uuid: node.value.uuid });
+            : resourceToBreadcrumb(node.value));
 };
 
 export const setSidePanelBreadcrumbs = (uuid: string) =>
@@ -52,9 +79,17 @@ export const setSidePanelBreadcrumbs = (uuid: string) =>
 
         if (uuidKind === ResourceKind.COLLECTION) {
             const collectionItem = item ? item : await services.collectionService.get(currentUuid);
+            const parentProcessItem = await getCollectionParent(collectionItem)(services);
+            if (parentProcessItem) {
+                breadcrumbs.push(resourceToBreadcrumb(parentProcessItem));
+            }
             dispatch(setBreadcrumbs(breadcrumbs, collectionItem));
         } else if (uuidKind === ResourceKind.PROCESS) {
             const processItem = await services.containerRequestService.get(currentUuid);
+            const parentProcessItem = await getProcessParent(processItem)(services);
+            if (parentProcessItem) {
+                breadcrumbs.push(resourceToBreadcrumb(parentProcessItem));
+            }
             dispatch(setBreadcrumbs(breadcrumbs, processItem));
         }
         dispatch(setBreadcrumbs(breadcrumbs));
@@ -70,28 +105,69 @@ export const setCategoryBreadcrumbs = (uuid: string, category: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         const ancestors = await services.ancestorsService.ancestors(uuid, '');
         dispatch(updateResources(ancestors));
-        const initialBreadcrumbs: ResourceBreadcrumb[] = [
+        const initialBreadcrumbs: Breadcrumb[] = [
             { label: category, uuid: category }
         ];
         const { collectionPanel: { item } } = getState();
         const path = getState().router.location!.pathname;
         const currentUuid = path.split('/')[2];
         const uuidKind = extractUuidKind(currentUuid);
-        const breadcrumbs = ancestors.reduce((breadcrumbs, ancestor) =>
+        let breadcrumbs = ancestors.reduce((breadcrumbs, ancestor) =>
             ancestor.kind === ResourceKind.GROUP
-                ? [...breadcrumbs, { label: ancestor.name, uuid: ancestor.uuid }]
+                ? [...breadcrumbs, resourceToBreadcrumb(ancestor)]
                 : breadcrumbs,
             initialBreadcrumbs);
         if (uuidKind === ResourceKind.COLLECTION) {
             const collectionItem = item ? item : await services.collectionService.get(currentUuid);
+            const parentProcessItem = await getCollectionParent(collectionItem)(services);
+            if (parentProcessItem) {
+                breadcrumbs.push(resourceToBreadcrumb(parentProcessItem));
+            }
             dispatch(setBreadcrumbs(breadcrumbs, collectionItem));
         } else if (uuidKind === ResourceKind.PROCESS) {
             const processItem = await services.containerRequestService.get(currentUuid);
+            const parentProcessItem = await getProcessParent(processItem)(services);
+            if (parentProcessItem) {
+                breadcrumbs.push(resourceToBreadcrumb(parentProcessItem));
+            }
             dispatch(setBreadcrumbs(breadcrumbs, processItem));
         }
         dispatch(setBreadcrumbs(breadcrumbs));
     };
 
+const getProcessParent = (childProcess: ContainerRequestResource) =>
+    async (services: ServiceRepository): Promise<ContainerRequestResource | undefined> => {
+        if (childProcess.requestingContainerUuid) {
+            const parentProcesses = await services.containerRequestService.list({
+                order: new OrderBuilder<ProcessResource>().addAsc('createdAt').getOrder(),
+                filters: new FilterBuilder().addEqual('container_uuid', childProcess.requestingContainerUuid).getFilters(),
+                select: containerRequestFieldsNoMounts,
+            });
+            if (parentProcesses.items.length > 0) {
+                return parentProcesses.items[0];
+            } else {
+                return undefined;
+            }
+        } else {
+            return undefined;
+        }
+    }
+
+const getCollectionParent = (collection: CollectionResource) =>
+    async (services: ServiceRepository): Promise<ContainerRequestResource | undefined> => {
+        const parentProcesses = await services.containerRequestService.list({
+            order: new OrderBuilder<ProcessResource>().addAsc('createdAt').getOrder(),
+            filters: new FilterBuilder().addEqual('output_uuid', collection.uuid).getFilters(),
+            select: containerRequestFieldsNoMounts,
+        });
+        if (parentProcesses.items.length > 0) {
+            return parentProcesses.items[0];
+        } else {
+            return undefined;
+        }
+    }
+
+
 export const setProjectBreadcrumbs = (uuid: string) =>
     (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
         const ancestors = getSidePanelTreeNodeAncestorsIds(uuid)(getState().treePicker);
@@ -121,7 +197,7 @@ export const setGroupDetailsBreadcrumbs = (groupUuid: string) =>
 
         const group = getResource<GroupResource>(groupUuid)(getState().resources);
 
-        const breadcrumbs: ResourceBreadcrumb[] = [
+        const breadcrumbs: Breadcrumb[] = [
             { label: SidePanelTreeCategory.GROUPS, uuid: SidePanelTreeCategory.GROUPS },
             { label: group ? group.name : (await services.groupsService.get(groupUuid)).name, uuid: groupUuid },
         ];
@@ -140,13 +216,13 @@ export const setUserProfileBreadcrumbs = (userUuid: string) =>
         try {
             const user = getResource<UserResource>(userUuid)(getState().resources)
                         || await services.userService.get(userUuid, false);
-            const breadcrumbs: ResourceBreadcrumb[] = [
+            const breadcrumbs: Breadcrumb[] = [
                 { label: USERS_PANEL_LABEL, uuid: USERS_PANEL_LABEL },
                 { label: user ? user.username : userUuid, uuid: userUuid },
             ];
             dispatch(setBreadcrumbs(breadcrumbs));
         } catch (e) {
-            const breadcrumbs: ResourceBreadcrumb[] = [
+            const breadcrumbs: Breadcrumb[] = [
                 { label: USERS_PANEL_LABEL, uuid: USERS_PANEL_LABEL },
                 { label: userUuid, uuid: userUuid },
             ];
diff --git a/src/views-components/breadcrumbs/breadcrumbs.ts b/src/views-components/breadcrumbs/breadcrumbs.ts
index c4134aed..0334097d 100644
--- a/src/views-components/breadcrumbs/breadcrumbs.ts
+++ b/src/views-components/breadcrumbs/breadcrumbs.ts
@@ -8,25 +8,24 @@ import { RootState } from 'store/store';
 import { Dispatch } from 'redux';
 import { navigateTo } from 'store/navigation/navigation-action';
 import { getProperty } from '../../store/properties/properties';
-import { ResourceBreadcrumb, BREADCRUMBS } from '../../store/breadcrumbs/breadcrumbs-actions';
+import { BREADCRUMBS } from '../../store/breadcrumbs/breadcrumbs-actions';
 import { openSidePanelContextMenu } from 'store/context-menu/context-menu-actions';
-import { ProjectResource } from "models/project";
 
 type BreadcrumbsDataProps = Pick<BreadcrumbsProps, 'items' | 'resources'>;
 type BreadcrumbsActionProps = Pick<BreadcrumbsProps, 'onClick' | 'onContextMenu'>;
 
 const mapStateToProps = () => ({ properties, resources }: RootState): BreadcrumbsDataProps => ({
-    items: (getProperty<ResourceBreadcrumb[]>(BREADCRUMBS)(properties) || []),
+    items: (getProperty<Breadcrumb[]>(BREADCRUMBS)(properties) || []),
     resources,
 });
 
 const mapDispatchToProps = (dispatch: Dispatch): BreadcrumbsActionProps => ({
-    onClick: ({ uuid }: Breadcrumb & ProjectResource) => {
+    onClick: ({ uuid }: Breadcrumb) => {
         dispatch<any>(navigateTo(uuid));
     },
-    onContextMenu: (event, breadcrumb: Breadcrumb & ProjectResource) => {
+    onContextMenu: (event, breadcrumb: Breadcrumb) => {
         dispatch<any>(openSidePanelContextMenu(event, breadcrumb.uuid));
     }
 });
 
-export const Breadcrumbs = connect(mapStateToProps(), mapDispatchToProps)(BreadcrumbsComponent);
\ No newline at end of file
+export const Breadcrumbs = connect(mapStateToProps(), mapDispatchToProps)(BreadcrumbsComponent);

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list