[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