owner-names-and-updated-navigating-on-data-explorer-name
authorPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Wed, 15 May 2019 12:57:03 +0000 (14:57 +0200)
committerPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Wed, 15 May 2019 12:57:03 +0000 (14:57 +0200)
Feature #15020

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

src/store/collection-panel/collection-panel-action.ts
src/store/collection-panel/collection-panel-reducer.ts
src/store/collections-content-address-panel/collections-content-address-middleware-service.ts
src/store/owner-name/owner-name-actions.ts [new file with mode: 0644]
src/store/owner-name/owner-name-reducer.ts [new file with mode: 0644]
src/store/store.ts
src/views-components/data-explorer/renderers.tsx
src/views-components/details-panel/collection-details.tsx
src/views-components/details-panel/details-panel.tsx
src/views/collection-content-address-panel/collection-content-address-panel.tsx

index 76a40dcbea4f09b50ce6129e485585dddd822ba0..b1dd8389611611940f2c270889dbaf5663bb3a25 100644 (file)
@@ -15,12 +15,10 @@ import { resourcesActions } from "~/store/resources/resources-actions";
 import { unionize, ofType, UnionOf } from '~/common/unionize';
 import { SnackbarKind } from '~/store/snackbar/snackbar-actions';
 import { navigateTo } from '~/store/navigation/navigation-action';
-import { FilterBuilder } from "~/services/api/filter-builder";
 import { loadDetailsPanel } from '~/store/details-panel/details-panel-action';
 
 export const collectionPanelActions = unionize({
     SET_COLLECTION: ofType<CollectionResource>(),
-    SET_NUMBER_OF_COLLECTIONS_WITH_SAME_PDH: ofType<number>(),
     LOAD_COLLECTION: ofType<{ uuid: string }>(),
     LOAD_COLLECTION_SUCCESS: ofType<{ item: CollectionResource }>()
 });
@@ -34,12 +32,6 @@ export const loadCollectionPanel = (uuid: string) =>
         dispatch(collectionPanelActions.LOAD_COLLECTION({ uuid }));
         dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES({ files: createTree() }));
         const collection = await services.collectionService.get(uuid);
-        const collectionsByPDH = await services.collectionService.list({
-            filters: new FilterBuilder()
-                .addEqual('portableDataHash', collection.portableDataHash)
-                .getFilters()
-        });
-        dispatch(collectionPanelActions.SET_NUMBER_OF_COLLECTIONS_WITH_SAME_PDH(collectionsByPDH.itemsAvailable));
         dispatch(loadDetailsPanel(collection.uuid));
         dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: collection }));
         dispatch(resourcesActions.SET_RESOURCES([collection]));
index 4207a3930410069a0871d5a4938d6df18a98fe1f..f09b019873e98e09b082a638a3f12a5b0eea93b2 100644 (file)
@@ -7,18 +7,15 @@ import { CollectionResource } from "~/models/collection";
 
 export interface CollectionPanelState {
     item: CollectionResource | null;
-    numberOfCollectionsWithSamePDH: number;
 }
 
 const initialState = {
-    item: null,
-    numberOfCollectionsWithSamePDH: 0
+    item: null
 };
 
 export const collectionPanelReducer = (state: CollectionPanelState = initialState, action: CollectionPanelAction) =>
     collectionPanelActions.match(action, {
         default: () => state,
         SET_COLLECTION: (item) => ({ ...state, item }),
-        LOAD_COLLECTION_SUCCESS: ({ item }) => ({ ...state, item }),
-        SET_NUMBER_OF_COLLECTIONS_WITH_SAME_PDH: (num) => ({ ...state, numberOfCollectionsWithSamePDH: num }),
+        LOAD_COLLECTION_SUCCESS: ({ item }) => ({ ...state, item })
     });
index 0e35d93fa68446b8c9eea15c6d365a8184c2017e..642e7b82666c176de9d805de927dc7a6846275cc 100644 (file)
@@ -21,6 +21,8 @@ import { navigateTo } from '~/store/navigation/navigation-action';
 import { updateFavorites } from '~/store/favorites/favorites-actions';
 import { updatePublicFavorites } from '~/store/public-favorites/public-favorites-actions';
 import { setBreadcrumbs } from '../breadcrumbs/breadcrumbs-actions';
+import { ResourceKind, extractUuidKind } from '~/models/resource';
+import { ownerNameActions } from '~/store/owner-name/owner-name-actions';
 
 export class CollectionsWithSameContentAddressMiddlewareService extends DataExplorerMiddlewareService {
     constructor(private services: ServiceRepository, id: string) {
@@ -57,6 +59,41 @@ export class CollectionsWithSameContentAddressMiddlewareService extends DataExpl
                         .addILike("name", dataExplorer.searchValue)
                         .getFilters()
                 });
+                const userUuids = response.items.map(it => {
+                    if (extractUuidKind(it.ownerUuid) === ResourceKind.USER) {
+                        return it.ownerUuid;
+                    } else {
+                        return '';
+                    }
+                }
+                );
+                const groupUuids = response.items.map(it => {
+                    if (extractUuidKind(it.ownerUuid) === ResourceKind.GROUP) {
+                        return it.ownerUuid;
+                    } else {
+                        return '';
+                    }
+                });
+                const responseUsers = await this.services.userService.list({
+                    limit: dataExplorer.rowsPerPage,
+                    offset: dataExplorer.page * dataExplorer.rowsPerPage,
+                    filters: new FilterBuilder()
+                        .addIn('uuid', userUuids)
+                        .getFilters()
+                });
+                const responseGroups = await this.services.groupsService.list({
+                    limit: dataExplorer.rowsPerPage,
+                    offset: dataExplorer.page * dataExplorer.rowsPerPage,
+                    filters: new FilterBuilder()
+                        .addIn('uuid', groupUuids)
+                        .getFilters()
+                });
+                responseUsers.items.map(it=>{
+                    api.dispatch<any>(ownerNameActions.SET_OWNER_NAME({name: it.uuid === userUuid ? 'User: Me' : `User: ${it.firstName} ${it.lastName}`, uuid: it.uuid}));
+                });
+                responseGroups.items.map(it=>{
+                    api.dispatch<any>(ownerNameActions.SET_OWNER_NAME({name: `Project: ${it.name}`, uuid: it.uuid}));
+                });
                 api.dispatch<any>(setBreadcrumbs([{ label: 'Projects', uuid: userUuid }]));
                 api.dispatch<any>(updateFavorites(response.items.map(item => item.uuid)));
                 api.dispatch<any>(updatePublicFavorites(response.items.map(item => item.uuid)));
diff --git a/src/store/owner-name/owner-name-actions.ts b/src/store/owner-name/owner-name-actions.ts
new file mode 100644 (file)
index 0000000..6c2784a
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { unionize, ofType, UnionOf } from '~/common/unionize';
+
+export const ownerNameActions = unionize({
+    SET_OWNER_NAME: ofType<OwnerNameState>()
+});
+
+interface OwnerNameState {
+    name: string;
+    uuid: string;
+}
+
+export type OwnerNameAction = UnionOf<typeof ownerNameActions>;
diff --git a/src/store/owner-name/owner-name-reducer.ts b/src/store/owner-name/owner-name-reducer.ts
new file mode 100644 (file)
index 0000000..58df209
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ownerNameActions, OwnerNameAction } from './owner-name-actions';
+
+export const ownerNameReducer = (state = [], action: OwnerNameAction) =>
+    ownerNameActions.match(action, {
+        SET_OWNER_NAME: data => [...state, { uuid: data.uuid, name: data.name }],
+        default: () => state,
+    });
\ No newline at end of file
index eff2454a4e46aa40b049df0b6ef1dd4b5cb71bf2..ff9a495e804b9e30c2f6693008d42e5a002943e5 100644 (file)
@@ -64,6 +64,7 @@ import { PUBLIC_FAVORITE_PANEL_ID } from '~/store/public-favorites-panel/public-
 import { publicFavoritesReducer } from '~/store/public-favorites/public-favorites-reducer';
 import { CollectionsWithSameContentAddressMiddlewareService } from '~/store/collections-content-address-panel/collections-content-address-middleware-service';
 import { COLLECTIONS_CONTENT_ADDRESS_PANEL_ID } from '~/store/collections-content-address-panel/collections-content-address-panel-actions';
+import { ownerNameReducer } from '~/store/owner-name/owner-name-reducer';
 
 const composeEnhancers =
     (process.env.NODE_ENV === 'development' &&
@@ -153,6 +154,7 @@ const createRootReducer = (services: ServiceRepository) => combineReducers({
     detailsPanel: detailsPanelReducer,
     dialog: dialogReducer,
     favorites: favoritesReducer,
+    ownerName: ownerNameReducer,
     publicFavorites: publicFavoritesReducer,
     form: formReducer,
     processLogsPanel: processLogsPanelReducer,
index 52760cb404e4cc28f801ff96aff69eaa52e8bac6..bf504f2b46b82e4efa475c1359cdf1a7c2c55f9e 100644 (file)
@@ -26,15 +26,14 @@ import { toggleIsActive, toggleIsAdmin } from '~/store/users/users-actions';
 import { LinkResource } from '~/models/link';
 import { navigateTo } from '~/store/navigation/navigation-action';
 import { withResourceData } from '~/views-components/data-explorer/with-resources';
-import { extractUuidKind } from '~/models/resource';
 
-const renderName = (item: { name: string; uuid: string, kind: string }) =>
+const renderName = (dispatch: Dispatch, item: { name: string; uuid: string, kind: string }) =>
     <Grid container alignItems="center" wrap="nowrap" spacing={16}>
         <Grid item>
             {renderIcon(item.kind)}
         </Grid>
         <Grid item>
-            <Typography color="primary" style={{ width: 'auto' }}>
+            <Typography color="primary" style={{ width: 'auto', cursor: 'pointer' }} onClick={() => dispatch<any>(navigateTo(item.uuid))}>
                 {item.name}
             </Typography>
         </Grid>
@@ -50,7 +49,7 @@ export const ResourceName = connect(
     (state: RootState, props: { uuid: string }) => {
         const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
         return resource || { name: '', uuid: '', kind: '' };
-    })(renderName);
+    })((resource: { name: string; uuid: string, kind: string } & DispatchProp<any>) => renderName(resource.dispatch, resource));
 
 const renderIcon = (kind: string) => {
     switch (kind) {
@@ -402,7 +401,7 @@ export const ResourceFileSize = connect(
     })((props: { fileSize?: number }) => renderFileSize(props.fileSize));
 
 const renderOwner = (owner: string) =>
-    <Typography noWrap color="primary" >
+    <Typography noWrap>
         {owner}
     </Typography>;
 
@@ -412,6 +411,14 @@ export const ResourceOwner = connect(
         return { owner: resource ? resource.ownerUuid : '' };
     })((props: { owner: string }) => renderOwner(props.owner));
 
+export const ResourceOwnerName = connect(
+    (state: RootState, props: { uuid: string }) => {
+        const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
+        const ownerNameState = state.ownerName;
+        const ownerName = ownerNameState.find(it => it.uuid === resource!.ownerUuid);
+        return { owner: ownerName ? ownerName!.name : resource!.ownerUuid };
+    })((props: { owner: string }) => renderOwner(props.owner));
+
 const renderType = (type: string) =>
     <Typography noWrap>
         {resourceLabel(type)}
index b47e9edf9c26c31d8953217cdb929fa4859da9cb..ec5bdabd833a097cac06b3eda5c30805ac5193be 100644 (file)
@@ -24,9 +24,8 @@ export class CollectionDetails extends DetailsData<CollectionResource> {
             <DetailsAttribute label='Owner' value={this.item.ownerUuid} lowercaseValue={true} />
             <DetailsAttribute label='Last modified' value={formatDate(this.item.modifiedAt)} />
             <DetailsAttribute label='Created at' value={formatDate(this.item.createdAt)} />
-            {/* Links but we dont have view */}
             <DetailsAttribute label='Collection UUID' linkInsideCard={this.item.uuid} value={this.item.uuid} />
-            <DetailsAttribute label='Content address' linkInsideCard={this.numberOfCollectionsByPDH === 1 ? this.item.uuid : this.item.portableDataHash} value={this.item.portableDataHash} />
+            <DetailsAttribute label='Content address' linkInsideCard={this.item.portableDataHash} value={this.item.portableDataHash} />
             {/* Missing attrs */}
             <DetailsAttribute label='Number of files' value={this.data && this.data.fileCount} />
             <DetailsAttribute label='Content size' value={formatFileSize(this.data && this.data.fileSize)} />
index 5c8ebe7479226b8a41e425201e1fb4d86315afab..be255cb7b378b66253075d320fcbcfb2b571949f 100644 (file)
@@ -79,14 +79,13 @@ const getItem = (res: DetailsResource, resourceData?: ResourceData, numberOfColl
     }
 };
 
-const mapStateToProps = ({ detailsPanel, resources, resourcesData, collectionPanelFiles, collectionPanel }: RootState) => {
+const mapStateToProps = ({ detailsPanel, resources, resourcesData, collectionPanelFiles }: RootState) => {
     const resource = getResource(detailsPanel.resourceUuid)(resources) as DetailsResource | undefined;
     const file = getNode(detailsPanel.resourceUuid)(collectionPanelFiles);
     const resourceData = getResourceData(detailsPanel.resourceUuid)(resourcesData);
-    const numberOfCollectionsByPDH = collectionPanel.numberOfCollectionsWithSamePDH;
     return {
         isOpened: detailsPanel.isOpened,
-        item: getItem(resource || (file && file.value) || EMPTY_RESOURCE, resourceData, numberOfCollectionsByPDH),
+        item: getItem(resource || (file && file.value) || EMPTY_RESOURCE, resourceData),
     };
 };
 
index 425588f1ed3517f6c19e639f33b963335ae7e7df..89b23f7c2fe4b8f2874057e883866ca772b6e33c 100644 (file)
@@ -20,7 +20,7 @@ import { navigateTo } from '~/store/navigation/navigation-action';
 import { DataColumns } from '~/components/data-table/data-table';
 import { SortDirection } from '~/components/data-table/data-column';
 import { createTree } from '~/models/tree';
-import { ResourceName, ResourceOwner, ResourceLastModifiedDate } from '~/views-components/data-explorer/renderers';
+import { ResourceName, ResourceOwnerName, ResourceLastModifiedDate } from '~/views-components/data-explorer/renderers';
 
 type CssRules = 'backLink' | 'backIcon' | 'card' | 'title' | 'iconHeader' | 'link';
 
@@ -77,7 +77,7 @@ export const collectionContentAddressPanelColumns: DataColumns<string> = [
         selected: true,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ResourceOwner uuid={uuid} />
+        render: uuid => <ResourceOwnerName uuid={uuid} />
     },
     {
         name: CollectionContentAddressPanelColumnNames.LAST_MODIFIED,