[ARVADOS-WORKBENCH2] created: 1.2.0-417-g4ecec1c

Git user git at public.curoverse.com
Wed Sep 19 06:28:41 EDT 2018


        at  4ecec1c730f1a3fcfd5082cdc14250d39dac199c (commit)


commit 4ecec1c730f1a3fcfd5082cdc14250d39dac199c
Author: Michal Klobukowski <michal.klobukowski at contractors.roche.com>
Date:   Wed Sep 19 12:28:28 2018 +0200

    Implement initial loading screen
    
    Feature #14185
    
    Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski at contractors.roche.com>

diff --git a/src/store/progress-indicator/progress-indicator-reducer.ts b/src/store/progress-indicator/progress-indicator-reducer.ts
index 849906b..89885af 100644
--- a/src/store/progress-indicator/progress-indicator-reducer.ts
+++ b/src/store/progress-indicator/progress-indicator-reducer.ts
@@ -27,3 +27,7 @@ export const progressIndicatorReducer = (state: ProgressIndicatorState = initial
 export function isSystemWorking(state: ProgressIndicatorState): boolean {
     return state.length > 0 && state.reduce((working, p) => working ? true : p.working, false);
 }
+
+export const getProgressIndicator = (id: string) =>
+    (state: ProgressIndicatorState) =>
+        state.find(state => state.id === id);
diff --git a/src/store/workbench/workbench-actions.ts b/src/store/workbench/workbench-actions.ts
index c79dc48..99f5bc7 100644
--- a/src/store/workbench/workbench-actions.ts
+++ b/src/store/workbench/workbench-actions.ts
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { Dispatch } from 'redux';
+import { Dispatch, AnyAction } from 'redux';
 import { RootState } from "../store";
 import { loadDetailsPanel } from '~/store/details-panel/details-panel-action';
 import { loadCollectionPanel } from '~/store/collection-panel/collection-panel-action';
@@ -38,11 +38,32 @@ import { initProcessLogsPanel } from '../process-logs-panel/process-logs-panel-a
 import { loadProcessPanel } from '~/store/process-panel/process-panel-actions';
 import { sharedWithMePanelActions } from '~/store/shared-with-me-panel/shared-with-me-panel-actions';
 import { loadSharedWithMePanel } from '../shared-with-me-panel/shared-with-me-panel-actions';
-
 import { CopyFormDialogData } from '~/store/copy-dialog/copy-dialog';
+import { progressIndicatorActions } from '~/store/progress-indicator/progress-indicator-actions';
+import { getProgressIndicator } from '../progress-indicator/progress-indicator-reducer';
+
+export const WORKBENCH_LOADING_SCREEN = 'workbenchLoadingScreen';
+
+export const isWorkbenchLoading = (state: RootState) => {
+    const progress = getProgressIndicator(WORKBENCH_LOADING_SCREEN)(state.progressIndicator);
+    return progress ? progress.working : false;
+};
+
+const handleFirstTimeLoad = (action: any) =>
+    async (dispatch: Dispatch<any>, getState: () => RootState) => {
+        try {
+            await dispatch(action);
+        } finally {
+            if (isWorkbenchLoading(getState())) {
+                dispatch(progressIndicatorActions.STOP_WORKING(WORKBENCH_LOADING_SCREEN));
+            }
+        }
+    };
+
 
 export const loadWorkbench = () =>
     async (dispatch: Dispatch, getState: () => RootState) => {
+        dispatch(progressIndicatorActions.START_WORKING(WORKBENCH_LOADING_SCREEN));
         const { auth, router } = getState();
         const { user } = auth;
         if (user) {
@@ -68,26 +89,29 @@ export const loadWorkbench = () =>
     };
 
 export const loadFavorites = () =>
-    (dispatch: Dispatch) => {
-        dispatch<any>(activateSidePanelTreeItem(SidePanelTreeCategory.FAVORITES));
-        dispatch<any>(loadFavoritePanel());
-        dispatch<any>(setSidePanelBreadcrumbs(SidePanelTreeCategory.FAVORITES));
-    };
+    handleFirstTimeLoad(
+        (dispatch: Dispatch) => {
+            dispatch<any>(activateSidePanelTreeItem(SidePanelTreeCategory.FAVORITES));
+            dispatch<any>(loadFavoritePanel());
+            dispatch<any>(setSidePanelBreadcrumbs(SidePanelTreeCategory.FAVORITES));
+        });
 
 export const loadTrash = () =>
-    (dispatch: Dispatch) => {
-        dispatch<any>(activateSidePanelTreeItem(SidePanelTreeCategory.TRASH));
-        dispatch<any>(loadTrashPanel());
-        dispatch<any>(setSidePanelBreadcrumbs(SidePanelTreeCategory.TRASH));
-    };
+    handleFirstTimeLoad(
+        (dispatch: Dispatch) => {
+            dispatch<any>(activateSidePanelTreeItem(SidePanelTreeCategory.TRASH));
+            dispatch<any>(loadTrashPanel());
+            dispatch<any>(setSidePanelBreadcrumbs(SidePanelTreeCategory.TRASH));
+        });
 
 export const loadProject = (uuid: string) =>
-    async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
-        dispatch(openProjectPanel(uuid));
-        await dispatch(activateSidePanelTreeItem(uuid));
-        dispatch(setProjectBreadcrumbs(uuid));
-        dispatch(loadDetailsPanel(uuid));
-    };
+    handleFirstTimeLoad(
+        async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+            dispatch(openProjectPanel(uuid));
+            await dispatch(activateSidePanelTreeItem(uuid));
+            dispatch(setProjectBreadcrumbs(uuid));
+            dispatch(loadDetailsPanel(uuid));
+        });
 
 export const createProject = (data: projectCreateActions.ProjectCreateFormDialogData) =>
     async (dispatch: Dispatch) => {
@@ -134,12 +158,13 @@ export const updateProject = (data: projectUpdateActions.ProjectUpdateFormDialog
     };
 
 export const loadCollection = (uuid: string) =>
-    async (dispatch: Dispatch) => {
-        const collection = await dispatch<any>(loadCollectionPanel(uuid));
-        await dispatch<any>(activateSidePanelTreeItem(collection.ownerUuid));
-        dispatch<any>(setCollectionBreadcrumbs(collection.uuid));
-        dispatch(loadDetailsPanel(uuid));
-    };
+    handleFirstTimeLoad(
+        async (dispatch: Dispatch) => {
+            const collection = await dispatch<any>(loadCollectionPanel(uuid));
+            await dispatch<any>(activateSidePanelTreeItem(collection.ownerUuid));
+            dispatch<any>(setCollectionBreadcrumbs(collection.uuid));
+            dispatch(loadDetailsPanel(uuid));
+        });
 
 export const createCollection = (data: collectionCreateActions.CollectionCreateFormDialogData) =>
     async (dispatch: Dispatch) => {
@@ -192,14 +217,14 @@ export const moveCollection = (data: MoveToFormDialogData) =>
     };
 
 export const loadProcess = (uuid: string) =>
-    async (dispatch: Dispatch, getState: () => RootState) => {
-        dispatch<any>(loadProcessPanel(uuid));
-        const process = await dispatch<any>(processesActions.loadProcess(uuid));
-        await dispatch<any>(activateSidePanelTreeItem(process.containerRequest.ownerUuid));
-        dispatch<any>(setProcessBreadcrumbs(uuid));
-        dispatch(loadDetailsPanel(uuid));
-
-    };
+    handleFirstTimeLoad(
+        async (dispatch: Dispatch, getState: () => RootState) => {
+            dispatch<any>(loadProcessPanel(uuid));
+            const process = await dispatch<any>(processesActions.loadProcess(uuid));
+            await dispatch<any>(activateSidePanelTreeItem(process.containerRequest.ownerUuid));
+            dispatch<any>(setProcessBreadcrumbs(uuid));
+            dispatch(loadDetailsPanel(uuid));
+        });
 
 export const updateProcess = (data: processUpdateActions.ProcessUpdateFormDialogData) =>
     async (dispatch: Dispatch) => {
@@ -243,12 +268,13 @@ export const copyProcess = (data: CopyFormDialogData) =>
     };
 
 export const loadProcessLog = (uuid: string) =>
-    async (dispatch: Dispatch) => {
-        const process = await dispatch<any>(processesActions.loadProcess(uuid));
-        dispatch<any>(setProcessBreadcrumbs(uuid));
-        dispatch<any>(initProcessLogsPanel(uuid));
-        await dispatch<any>(activateSidePanelTreeItem(process.containerRequest.ownerUuid));
-    };
+    handleFirstTimeLoad(
+        async (dispatch: Dispatch) => {
+            const process = await dispatch<any>(processesActions.loadProcess(uuid));
+            dispatch<any>(setProcessBreadcrumbs(uuid));
+            dispatch<any>(initProcessLogsPanel(uuid));
+            await dispatch<any>(activateSidePanelTreeItem(process.containerRequest.ownerUuid));
+        });
 
 export const resourceIsNotLoaded = (uuid: string) =>
     snackbarActions.OPEN_SNACKBAR({
@@ -271,8 +297,8 @@ export const reloadProjectMatchingUuid = (matchingUuids: string[]) =>
         }
     };
 
-export const loadSharedWithMe = (dispatch: Dispatch) => {
-    dispatch<any>(activateSidePanelTreeItem(SidePanelTreeCategory.SHARED_WITH_ME));
+export const loadSharedWithMe = handleFirstTimeLoad(async (dispatch: Dispatch) => {
     dispatch<any>(loadSharedWithMePanel());
-    dispatch<any>(setSidePanelBreadcrumbs(SidePanelTreeCategory.SHARED_WITH_ME));
-};
+    await dispatch<any>(activateSidePanelTreeItem(SidePanelTreeCategory.SHARED_WITH_ME));
+    await dispatch<any>(setSidePanelBreadcrumbs(SidePanelTreeCategory.SHARED_WITH_ME));
+});
diff --git a/src/views/workbench/workbench-loading-screen.tsx b/src/views/workbench/workbench-loading-screen.tsx
new file mode 100644
index 0000000..e8f9a28
--- /dev/null
+++ b/src/views/workbench/workbench-loading-screen.tsx
@@ -0,0 +1,32 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { Grid, CircularProgress } from '@material-ui/core';
+
+type CssRules = 'root' | 'img';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+    img: {
+        marginBottom: theme.spacing.unit * 4
+    },
+    root: {
+        background: theme.palette.background.default,
+        bottom: 0,
+        left: 0,
+        position: 'fixed',
+        right: 0,
+        top: 0,
+        zIndex: theme.zIndex.appBar + 1,
+    }
+});
+
+export const WorkbenchLoadingScreen = withStyles(styles)(({ classes }: WithStyles<CssRules>) =>
+    <Grid container direction="column" alignItems='center' justify='center' className={classes.root}>
+        <img src='https://arvados.org/images/img01.png' className={classes.img} />
+        <CircularProgress />
+    </Grid>
+);
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index ad1a266..5cea296 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -46,6 +46,8 @@ import { SharedWithMePanel } from '../shared-with-me-panel/shared-with-me-panel'
 import SplitterLayout from 'react-splitter-layout';
 import { ProcessCommandDialog } from '~/views-components/process-command-dialog/process-command-dialog';
 import { isSystemWorking } from "~/store/progress-indicator/progress-indicator-reducer";
+import { WorkbenchLoadingScreen } from './workbench-loading-screen';
+import { isWorkbenchLoading } from '../../store/workbench/workbench-actions';
 
 type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content' | 'appBar';
 
@@ -86,6 +88,7 @@ interface WorkbenchDataProps {
     user?: User;
     currentToken?: string;
     working: boolean;
+    loading: boolean;
 }
 
 interface WorkbenchGeneralProps {
@@ -104,7 +107,8 @@ export const Workbench = withStyles(styles)(
         (state: RootState) => ({
             user: state.auth.user,
             currentToken: state.auth.apiToken,
-            working: isSystemWorking(state.progressIndicator)
+            working: isSystemWorking(state.progressIndicator),
+            loading: isWorkbenchLoading(state),
         })
     )(
         class extends React.Component<WorkbenchProps, WorkbenchState> {
@@ -112,69 +116,71 @@ export const Workbench = withStyles(styles)(
                 searchText: "",
             };
             render() {
-                const { classes } = this.props;
-                return <>
-                    <MainAppBar
-                        searchText={this.state.searchText}
-                        user={this.props.user}
-                        onSearch={this.onSearch}
-                        buildInfo={this.props.buildInfo}>
-                        {this.props.working ? <LinearProgress color="secondary" /> : null}
-                    </MainAppBar>
-                    <Grid container direction="column" className={classes.root}>
-                        {this.props.user &&
-                            <Grid container item xs alignItems="stretch" wrap="nowrap">
-                                <Grid container item className={classes.container}>
-                                <SplitterLayout customClassName={classes.splitter} percentage={true}
-                                    primaryIndex={0} primaryMinSize={20} secondaryInitialSize={80} secondaryMinSize={40}>
-                                        <Grid container item xs component='aside' direction='column' className={classes.asidePanel}>
-                                            <SidePanel />
-                                        </Grid>
-                                        <Grid container item xs component="main" direction="column" className={classes.contentWrapper}>
-                                            <Grid item>
-                                                <MainContentBar />
+                const { classes, loading } = this.props;
+                return loading
+                    ? <WorkbenchLoadingScreen />
+                    : <>
+                        <MainAppBar
+                            searchText={this.state.searchText}
+                            user={this.props.user}
+                            onSearch={this.onSearch}
+                            buildInfo={this.props.buildInfo}>
+                            {this.props.working ? <LinearProgress color="secondary" /> : null}
+                        </MainAppBar>
+                        <Grid container direction="column" className={classes.root}>
+                            {this.props.user &&
+                                <Grid container item xs alignItems="stretch" wrap="nowrap">
+                                    <Grid container item className={classes.container}>
+                                        <SplitterLayout customClassName={classes.splitter} percentage={true}
+                                            primaryIndex={0} primaryMinSize={20} secondaryInitialSize={80} secondaryMinSize={40}>
+                                            <Grid container item xs component='aside' direction='column' className={classes.asidePanel}>
+                                                <SidePanel />
                                             </Grid>
-                                            <Grid item xs className={classes.content}>
-                                                <Switch>
-                                                    <Route path={Routes.PROJECTS} component={ProjectPanel} />
-                                                    <Route path={Routes.COLLECTIONS} component={CollectionPanel} />
-                                                    <Route path={Routes.FAVORITES} component={FavoritePanel} />
-                                                    <Route path={Routes.PROCESSES} component={ProcessPanel} />
-                                                    <Route path={Routes.TRASH} component={TrashPanel} />
-                                                    <Route path={Routes.PROCESS_LOGS} component={ProcessLogPanel} />
-                                                    <Route path={Routes.SHARED_WITH_ME} component={SharedWithMePanel} />
-                                                </Switch>
+                                            <Grid container item xs component="main" direction="column" className={classes.contentWrapper}>
+                                                <Grid item>
+                                                    <MainContentBar />
+                                                </Grid>
+                                                <Grid item xs className={classes.content}>
+                                                    <Switch>
+                                                        <Route path={Routes.PROJECTS} component={ProjectPanel} />
+                                                        <Route path={Routes.COLLECTIONS} component={CollectionPanel} />
+                                                        <Route path={Routes.FAVORITES} component={FavoritePanel} />
+                                                        <Route path={Routes.PROCESSES} component={ProcessPanel} />
+                                                        <Route path={Routes.TRASH} component={TrashPanel} />
+                                                        <Route path={Routes.PROCESS_LOGS} component={ProcessLogPanel} />
+                                                        <Route path={Routes.SHARED_WITH_ME} component={SharedWithMePanel} />
+                                                    </Switch>
+                                                </Grid>
                                             </Grid>
-                                        </Grid>
-                                    </SplitterLayout>
+                                        </SplitterLayout>
+                                    </Grid>
+                                    <Grid item>
+                                        <DetailsPanel />
+                                    </Grid>
                                 </Grid>
-                                <Grid item>
-                                    <DetailsPanel />
-                                </Grid>
-                            </Grid>
-                        }
-                    </Grid>
-                    <ContextMenu />
-                    <CopyCollectionDialog />
-                    <CopyProcessDialog />
-                    <CreateCollectionDialog />
-                    <CreateProjectDialog />
-                    <CurrentTokenDialog />
-                    <FileRemoveDialog />
-                    <FileRemoveDialog />
-                    <FilesUploadCollectionDialog />
-                    <MoveCollectionDialog />
-                    <MoveProcessDialog />
-                    <MoveProjectDialog />
-                    <MultipleFilesRemoveDialog />
-                    <PartialCopyCollectionDialog />
-                    <ProcessCommandDialog />
-                    <RenameFileDialog />
-                    <Snackbar />
-                    <UpdateCollectionDialog />
-                    <UpdateProcessDialog />
-                    <UpdateProjectDialog />
-                </>;
+                            }
+                        </Grid>
+                        <ContextMenu />
+                        <CopyCollectionDialog />
+                        <CopyProcessDialog />
+                        <CreateCollectionDialog />
+                        <CreateProjectDialog />
+                        <CurrentTokenDialog />
+                        <FileRemoveDialog />
+                        <FileRemoveDialog />
+                        <FilesUploadCollectionDialog />
+                        <MoveCollectionDialog />
+                        <MoveProcessDialog />
+                        <MoveProjectDialog />
+                        <MultipleFilesRemoveDialog />
+                        <PartialCopyCollectionDialog />
+                        <ProcessCommandDialog />
+                        <RenameFileDialog />
+                        <Snackbar />
+                        <UpdateCollectionDialog />
+                        <UpdateProcessDialog />
+                        <UpdateProjectDialog />
+                    </>;
             }
 
             onSearch = (searchText: string) => {

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list