15610: Shows status indicator while loading collection's file data.
authorLucas Di Pentima <lucas@di-pentima.com.ar>
Fri, 12 Jun 2020 20:54:31 +0000 (17:54 -0300)
committerLucas Di Pentima <lucas@di-pentima.com.ar>
Fri, 12 Jun 2020 20:54:31 +0000 (17:54 -0300)
This includes the general app progress indicator, and a '(loading files...)'
text label where the file tree should be rendered.

Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas@di-pentima.com.ar>

src/components/collection-panel-files/collection-panel-files.tsx
src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
src/views/collection-panel/collection-panel.tsx

index 48b36be16ada976777bad3b161bd803ba57d87f0..3a2d55fbc95c87d1285572c661d7bad894bacdfc 100644 (file)
@@ -13,6 +13,7 @@ import { DownloadIcon } from '~/components/icon/icon';
 export interface CollectionPanelFilesProps {
     items: Array<TreeItem<FileTreeData>>;
     isWritable: boolean;
 export interface CollectionPanelFilesProps {
     items: Array<TreeItem<FileTreeData>>;
     isWritable: boolean;
+    isLoading: boolean;
     onUploadDataClick: () => void;
     onItemMenuOpen: (event: React.MouseEvent<HTMLElement>, item: TreeItem<FileTreeData>, isWritable: boolean) => void;
     onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, isWritable: boolean) => void;
     onUploadDataClick: () => void;
     onItemMenuOpen: (event: React.MouseEvent<HTMLElement>, item: TreeItem<FileTreeData>, isWritable: boolean) => void;
     onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, isWritable: boolean) => void;
@@ -22,7 +23,7 @@ export interface CollectionPanelFilesProps {
     currentItemUuid?: string;
 }
 
     currentItemUuid?: string;
 }
 
-type CssRules = 'root' | 'cardSubheader' | 'nameHeader' | 'fileSizeHeader' | 'uploadIcon' | 'button';
+type CssRules = 'root' | 'cardSubheader' | 'nameHeader' | 'fileSizeHeader' | 'uploadIcon' | 'button' | 'centeredLabel';
 
 const styles: StyleRulesCallback<CssRules> = theme => ({
     root: {
 
 const styles: StyleRulesCallback<CssRules> = theme => ({
     root: {
@@ -44,12 +45,17 @@ const styles: StyleRulesCallback<CssRules> = theme => ({
     button: {
         marginRight: -theme.spacing.unit,
         marginTop: '0px'
     button: {
         marginRight: -theme.spacing.unit,
         marginTop: '0px'
-    }
+    },
+    centeredLabel: {
+        fontSize: '0.875rem',
+        textAlign: 'center'
+    },
 });
 
 export const CollectionPanelFiles =
     withStyles(styles)(
 });
 
 export const CollectionPanelFiles =
     withStyles(styles)(
-        ({ onItemMenuOpen, onOptionsMenuOpen, onUploadDataClick, classes, isWritable, ...treeProps }: CollectionPanelFilesProps & WithStyles<CssRules>) =>
+        ({ onItemMenuOpen, onOptionsMenuOpen, onUploadDataClick, classes,
+            isWritable, isLoading, ...treeProps }: CollectionPanelFilesProps & WithStyles<CssRules>) =>
             <Card data-cy='collection-files-panel' className={classes.root}>
                 <CardHeader
                     title="Files"
             <Card data-cy='collection-files-panel' className={classes.root}>
                 <CardHeader
                     title="Files"
@@ -85,5 +91,7 @@ export const CollectionPanelFiles =
                         File size
                     </Typography>
                 </Grid>
                         File size
                     </Typography>
                 </Grid>
-                <FileTree onMenuOpen={(ev, item) => onItemMenuOpen(ev, item, isWritable)} {...treeProps} />
+                { isLoading
+                ? <div className={classes.centeredLabel}>(loading files...)</div>
+                : <FileTree onMenuOpen={(ev, item) => onItemMenuOpen(ev, item, isWritable)} {...treeProps} /> }
             </Card>);
             </Card>);
index 9d3ae86165ed5d786b00a7e12aae3319d9f4d288..fe93eef2fed1576f2fbb71796d32ece808342d74 100644 (file)
@@ -14,6 +14,7 @@ import { filterCollectionFilesBySelection } from './collection-panel-files-state
 import { startSubmit, stopSubmit, initialize, FormErrors } from 'redux-form';
 import { getDialog } from "~/store/dialog/dialog-reducer";
 import { getFileFullPath, sortFilesTree } from "~/services/collection-service/collection-service-files-response";
 import { startSubmit, stopSubmit, initialize, FormErrors } from 'redux-form';
 import { getDialog } from "~/store/dialog/dialog-reducer";
 import { getFileFullPath, sortFilesTree } from "~/services/collection-service/collection-service-files-response";
+import { progressIndicatorActions } from "~/store/progress-indicator/progress-indicator-actions";
 
 export const collectionPanelFilesAction = unionize({
     SET_COLLECTION_FILES: ofType<CollectionFilesTree>(),
 
 export const collectionPanelFilesAction = unionize({
     SET_COLLECTION_FILES: ofType<CollectionFilesTree>(),
@@ -25,8 +26,11 @@ export const collectionPanelFilesAction = unionize({
 
 export type CollectionPanelFilesAction = UnionOf<typeof collectionPanelFilesAction>;
 
 
 export type CollectionPanelFilesAction = UnionOf<typeof collectionPanelFilesAction>;
 
+export const COLLECTION_PANEL_LOAD_FILES = 'collectionPanelLoadFiles';
+
 export const loadCollectionFiles = (uuid: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
 export const loadCollectionFiles = (uuid: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PANEL_LOAD_FILES));
         const files = await services.collectionService.files(uuid);
 
         // Given the array of directories and files, create the appropriate tree nodes,
         const files = await services.collectionService.files(uuid);
 
         // Given the array of directories and files, create the appropriate tree nodes,
@@ -35,6 +39,7 @@ export const loadCollectionFiles = (uuid: string) =>
         const sorted = sortFilesTree(tree);
         const mapped = mapTreeValues(services.collectionService.extendFileURL)(sorted);
         dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES(mapped));
         const sorted = sortFilesTree(tree);
         const mapped = mapTreeValues(services.collectionService.extendFileURL)(sorted);
         dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES(mapped));
+        dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PANEL_LOAD_FILES));
     };
 
 export const removeCollectionFiles = (filePaths: string[]) =>
     };
 
 export const removeCollectionFiles = (filePaths: string[]) =>
index 3662538774ea9d3116c42bcd878f8483d41b57f1..27a685410116fb238e44c50f7a2808aef142b1d2 100644 (file)
@@ -28,6 +28,8 @@ import { IllegalNamingWarning } from '~/components/warning/warning';
 import { GroupResource } from '~/models/group';
 import { UserResource } from '~/models/user';
 import { getUserUuid } from '~/common/getuser';
 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';
 
 type CssRules = 'card' | 'iconHeader' | 'tag' | 'label' | 'value' | 'link' | 'centeredLabel' | 'readOnlyIcon';
 
 
 type CssRules = 'card' | 'iconHeader' | 'tag' | 'label' | 'value' | 'link' | 'centeredLabel' | 'readOnlyIcon';
 
@@ -70,6 +72,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
 interface CollectionPanelDataProps {
     item: CollectionResource;
     isWritable: boolean;
 interface CollectionPanelDataProps {
     item: CollectionResource;
     isWritable: boolean;
+    isLoadingFiles: boolean;
 }
 
 type CollectionPanelProps = CollectionPanelDataProps & DispatchProp
 }
 
 type CollectionPanelProps = CollectionPanelDataProps & DispatchProp
@@ -88,11 +91,13 @@ export const CollectionPanel = withStyles(styles)(
                 isWritable = itemOwner.writableBy.indexOf(currentUserUUID || '') >= 0;
             }
         }
                 isWritable = itemOwner.writableBy.indexOf(currentUserUUID || '') >= 0;
             }
         }
-        return { item, isWritable };
+        const loadingFilesIndicator = getProgressIndicator(COLLECTION_PANEL_LOAD_FILES)(state.progressIndicator);
+        const isLoadingFiles = loadingFilesIndicator && loadingFilesIndicator!.working || false;
+        return { item, isWritable, isLoadingFiles };
     })(
         class extends React.Component<CollectionPanelProps> {
             render() {
     })(
         class extends React.Component<CollectionPanelProps> {
             render() {
-                const { classes, item, dispatch, isWritable } = this.props;
+                const { classes, item, dispatch, isWritable, isLoadingFiles } = this.props;
                 return item
                     ? <>
                         <Card data-cy='collection-info-panel' className={classes.card}>
                 return item
                     ? <>
                         <Card data-cy='collection-info-panel' className={classes.card}>
@@ -183,7 +188,7 @@ export const CollectionPanel = withStyles(styles)(
                             </CardContent>
                         </Card>
                         <div className={classes.card}>
                             </CardContent>
                         </Card>
                         <div className={classes.card}>
-                            <CollectionPanelFiles isWritable={isWritable} />
+                            <CollectionPanelFiles isWritable={isWritable} isLoading={isLoadingFiles} />
                         </div>
                     </>
                     : null;
                         </div>
                     </>
                     : null;