From 7131c732cffb1383099b5e1593b3ee4b48635df5 Mon Sep 17 00:00:00 2001 From: Lucas Di Pentima Date: Mon, 15 Jun 2020 16:03:58 -0300 Subject: [PATCH] 15610: Avoids loading the file list on big collections, offers manual loading. After the previous performance enhancements, 75% of the time spent to show the collection's files goes to the WebDAV request + parsing, so to avoid inadvertently freezing the UI, when the file_count field passes a predefined value (now 40k files), the user gets the option to manually load the file listing by clicking on a button. Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima --- .../collection-panel-files.tsx | 55 +++++++++++-------- .../collection-panel-action.ts | 10 +++- .../collection-panel-files-actions.ts | 1 + .../collection-panel-reducer.ts | 13 ++++- .../collection-panel/collection-panel.tsx | 20 +++++-- 5 files changed, 65 insertions(+), 34 deletions(-) diff --git a/src/components/collection-panel-files/collection-panel-files.tsx b/src/components/collection-panel-files/collection-panel-files.tsx index 3a2d55fb..4d7e9384 100644 --- a/src/components/collection-panel-files/collection-panel-files.tsx +++ b/src/components/collection-panel-files/collection-panel-files.tsx @@ -14,12 +14,14 @@ export interface CollectionPanelFilesProps { items: Array>; isWritable: boolean; isLoading: boolean; + tooManyFiles: boolean; onUploadDataClick: () => void; onItemMenuOpen: (event: React.MouseEvent, item: TreeItem, isWritable: boolean) => void; onOptionsMenuOpen: (event: React.MouseEvent, isWritable: boolean) => void; onSelectionToggle: (event: React.MouseEvent, item: TreeItem) => void; onCollapseToggle: (id: string, status: TreeItemStatus) => void; onFileClick: (id: string) => void; + loadFilesFunc: () => void; currentItemUuid?: string; } @@ -55,7 +57,7 @@ const styles: StyleRulesCallback = theme => ({ export const CollectionPanelFiles = withStyles(styles)( ({ onItemMenuOpen, onOptionsMenuOpen, onUploadDataClick, classes, - isWritable, isLoading, ...treeProps }: CollectionPanelFilesProps & WithStyles) => + isWritable, isLoading, tooManyFiles, loadFilesFunc, ...treeProps }: CollectionPanelFilesProps & WithStyles) => } /> - - onOptionsMenuOpen(ev, isWritable)}> - - - - } /> - - - Name - - - File size - - - { isLoading - ?
(loading files...)
- : onItemMenuOpen(ev, item, isWritable)} {...treeProps} /> } + { tooManyFiles + ?
+ File listing may take some time, please click to browse: +
+ : <> + + onOptionsMenuOpen(ev, isWritable)}> + + + + } /> + + + Name + + + File size + + + { isLoading + ?
(loading files...)
+ : onItemMenuOpen(ev, item, isWritable)} {...treeProps} /> } + + }
); diff --git a/src/store/collection-panel/collection-panel-action.ts b/src/store/collection-panel/collection-panel-action.ts index 9922d8b5..35c3c3d3 100644 --- a/src/store/collection-panel/collection-panel-action.ts +++ b/src/store/collection-panel/collection-panel-action.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0 import { Dispatch } from "redux"; -import { loadCollectionFiles } from "./collection-panel-files/collection-panel-files-actions"; +import { loadCollectionFiles, COLLECTION_PANEL_LOAD_FILES_THRESHOLD } from "./collection-panel-files/collection-panel-files-actions"; import { CollectionResource } from '~/models/collection'; import { collectionPanelFilesAction } from "./collection-panel-files/collection-panel-files-actions"; import { createTree } from "~/models/tree"; @@ -21,7 +21,8 @@ import { addProperty, deleteProperty } from "~/lib/resource-properties"; export const collectionPanelActions = unionize({ SET_COLLECTION: ofType(), LOAD_COLLECTION: ofType<{ uuid: string }>(), - LOAD_COLLECTION_SUCCESS: ofType<{ item: CollectionResource }>() + LOAD_COLLECTION_SUCCESS: ofType<{ item: CollectionResource }>(), + LOAD_BIG_COLLECTIONS: ofType(), }); export type CollectionPanelAction = UnionOf; @@ -36,7 +37,10 @@ export const loadCollectionPanel = (uuid: string) => dispatch(loadDetailsPanel(collection.uuid)); dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: collection })); dispatch(resourcesActions.SET_RESOURCES([collection])); - dispatch(loadCollectionFiles(collection.uuid)); + if (collection.fileCount <= COLLECTION_PANEL_LOAD_FILES_THRESHOLD && + !getState().collectionPanel.loadBigCollections) { + dispatch(loadCollectionFiles(collection.uuid)); + } return collection; }; diff --git a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts index fe93eef2..204d4c0e 100644 --- a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts +++ b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts @@ -27,6 +27,7 @@ export const collectionPanelFilesAction = unionize({ export type CollectionPanelFilesAction = UnionOf; export const COLLECTION_PANEL_LOAD_FILES = 'collectionPanelLoadFiles'; +export const COLLECTION_PANEL_LOAD_FILES_THRESHOLD = 40000; export const loadCollectionFiles = (uuid: string) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { diff --git a/src/store/collection-panel/collection-panel-reducer.ts b/src/store/collection-panel/collection-panel-reducer.ts index f09b0198..18590181 100644 --- a/src/store/collection-panel/collection-panel-reducer.ts +++ b/src/store/collection-panel/collection-panel-reducer.ts @@ -7,15 +7,22 @@ import { CollectionResource } from "~/models/collection"; export interface CollectionPanelState { item: CollectionResource | null; + loadBigCollections: boolean; } const initialState = { - item: null + item: null, + loadBigCollections: false, }; 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_COLLECTION: (item) => ({ + ...state, + item, + loadBigCollections: false, + }), + LOAD_COLLECTION_SUCCESS: ({ item }) => ({ ...state, item }), + LOAD_BIG_COLLECTIONS: (loadBigCollections) => ({ ...state, loadBigCollections}), }); diff --git a/src/views/collection-panel/collection-panel.tsx b/src/views/collection-panel/collection-panel.tsx index 27a68541..1cfa48de 100644 --- a/src/views/collection-panel/collection-panel.tsx +++ b/src/views/collection-panel/collection-panel.tsx @@ -16,7 +16,7 @@ import { DetailsAttribute } from '~/components/details-attribute/details-attribu import { CollectionResource } from '~/models/collection'; import { CollectionPanelFiles } from '~/views-components/collection-panel-files/collection-panel-files'; import { CollectionTagForm } from './collection-tag-form'; -import { deleteCollectionTag, navigateToProcess } from '~/store/collection-panel/collection-panel-action'; +import { deleteCollectionTag, navigateToProcess, collectionPanelActions } from '~/store/collection-panel/collection-panel-action'; import { getResource } from '~/store/resources/resources'; import { openContextMenu } from '~/store/context-menu/context-menu-actions'; import { ContextMenuKind } from '~/views-components/context-menu/context-menu'; @@ -29,7 +29,7 @@ import { GroupResource } from '~/models/group'; import { UserResource } from '~/models/user'; import { getUserUuid } from '~/common/getuser'; import { getProgressIndicator } from '~/store/progress-indicator/progress-indicator-reducer'; -import { COLLECTION_PANEL_LOAD_FILES } from '~/store/collection-panel/collection-panel-files/collection-panel-files-actions'; +import { COLLECTION_PANEL_LOAD_FILES, loadCollectionFiles, COLLECTION_PANEL_LOAD_FILES_THRESHOLD } from '~/store/collection-panel/collection-panel-files/collection-panel-files-actions'; type CssRules = 'card' | 'iconHeader' | 'tag' | 'label' | 'value' | 'link' | 'centeredLabel' | 'readOnlyIcon'; @@ -73,6 +73,7 @@ interface CollectionPanelDataProps { item: CollectionResource; isWritable: boolean; isLoadingFiles: boolean; + tooManyFiles: boolean; } type CollectionPanelProps = CollectionPanelDataProps & DispatchProp @@ -93,11 +94,12 @@ export const CollectionPanel = withStyles(styles)( } const loadingFilesIndicator = getProgressIndicator(COLLECTION_PANEL_LOAD_FILES)(state.progressIndicator); const isLoadingFiles = loadingFilesIndicator && loadingFilesIndicator!.working || false; - return { item, isWritable, isLoadingFiles }; + const tooManyFiles = !state.collectionPanel.loadBigCollections && item && item.fileCount > COLLECTION_PANEL_LOAD_FILES_THRESHOLD || false; + return { item, isWritable, isLoadingFiles, tooManyFiles }; })( class extends React.Component { render() { - const { classes, item, dispatch, isWritable, isLoadingFiles } = this.props; + const { classes, item, dispatch, isWritable, isLoadingFiles, tooManyFiles } = this.props; return item ? <> @@ -188,7 +190,15 @@ export const CollectionPanel = withStyles(styles)(
- + { + dispatch(collectionPanelActions.LOAD_BIG_COLLECTIONS(true)); + dispatch(loadCollectionFiles(this.props.item.uuid)); + } + } />
: null; -- 2.30.2