import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider } from "react-redux";
-import { Workbench } from './views/workbench/workbench';
+import { MainPanel } from './views/main-panel/main-panel';
import './index.css';
import { Route } from 'react-router';
import createBrowserHistory from "history/createBrowserHistory";
import { setCurrentTokenDialogApiHost } from '~/store/current-token-dialog/current-token-dialog-actions';
import { processResourceActionSet } from './views-components/context-menu/action-sets/process-resource-action-set';
import { progressIndicatorActions } from '~/store/progress-indicator/progress-indicator-actions';
-import { snackbarActions, SnackbarKind } from "~/store/snackbar/snackbar-actions";
const getBuildNumber = () => "BN-" + (process.env.REACT_APP_BUILD_NUMBER || "dev");
const getGitCommit = () => "GIT-" + (process.env.REACT_APP_GIT_COMMIT || "latest").substr(0, 7);
store.dispatch(setCurrentTokenDialogApiHost(apiHost));
const TokenComponent = (props: any) => <ApiToken authService={services.authService} {...props} />;
- const WorkbenchComponent = (props: any) => <Workbench authService={services.authService} buildInfo={buildInfo} {...props} />;
+ const MainPanelComponent = (props: any) => <MainPanel buildInfo={buildInfo} {...props} />;
const App = () =>
<MuiThemeProvider theme={CustomTheme}>
<ConnectedRouter history={history}>
<div>
<Route path={Routes.TOKEN} component={TokenComponent} />
- <Route path={Routes.ROOT} component={WorkbenchComponent} />
+ <Route path={Routes.ROOT} component={MainPanelComponent} />
</div>
</ConnectedRouter>
</Provider>
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);
favoritePanelMiddleware,
trashPanelMiddleware,
sharedWithMePanelMiddleware,
+ workflowPanelMiddleware
];
const enhancer = composeEnhancers(applyMiddleware(...middlewares));
return createStore(rootReducer, enhancer);
//
// 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';
import { CopyFormDialogData } from '~/store/copy-dialog/copy-dialog';
import { loadWorkflowPanel, workflowPanelActions } from '~/store/workflow-panel/workflow-panel-actions';
import { workflowPanelColumns } from '~/views/workflow-panel/workflow-panel';
+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) {
dispatch(favoritePanelActions.SET_COLUMNS({ columns: favoritePanelColumns }));
dispatch(trashPanelActions.SET_COLUMNS({ columns: trashPanelColumns }));
dispatch(sharedWithMePanelActions.SET_COLUMNS({ columns: projectPanelColumns }));
- dispatch(workflowPanelActions.SET_COLUMNS({ columns: workflowPanelColumns}));
+ dispatch(workflowPanelActions.SET_COLUMNS({ columns: workflowPanelColumns }));
dispatch<any>(initSidePanelTree());
if (router.location) {
const match = matchRootRoute(router.location.pathname);
};
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) => {
};
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) => {
};
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) => {
};
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({
}
};
-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));
+});
-export const loadWorkflow = (dispatch: Dispatch<any>) => {
+export const loadWorkflow = handleFirstTimeLoad(async (dispatch: Dispatch<any>) => {
dispatch(activateSidePanelTreeItem(SidePanelTreeCategory.WORKFLOWS));
- dispatch(loadWorkflowPanel());
+ await dispatch(loadWorkflowPanel());
dispatch(setSidePanelBreadcrumbs(SidePanelTreeCategory.WORKFLOWS));
-};
+});
import { DataExplorerMiddlewareService, dataExplorerToListParams, listResultsToDataExplorerItemsMeta } from '~/store/data-explorer/data-explorer-middleware-service';
import { RootState } from '~/store/store';
import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
-import { DataExplorer } from '~/store/data-explorer/data-explorer-reducer';
+import { DataExplorer, getDataExplorer } from '~/store/data-explorer/data-explorer-reducer';
import { updateResources } from '~/store/resources/resources-actions';
import { FilterBuilder } from '~/services/api/filter-builder';
import { SortDirection } from '~/components/data-table/data-column';
}
async requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
+ const state = api.getState();
+ const dataExplorer = getDataExplorer(state.dataExplorer, this.getId());
try {
- const response = await this.services.workflowService;
- api.dispatch(updateResources([]));
- api.dispatch(setItems({ kind: '', offset: 4, limit: 4, items: [], itemsAvailable: 4 }));
+ const response = await this.services.workflowService.list({ order: getOrder(dataExplorer) });
+ api.dispatch(updateResources(response.items));
+ api.dispatch(setItems(response));
} catch {
api.dispatch(couldNotFetchWorkflows());
}
interface Props {
id: string;
onRowClick: (item: any) => void;
- onContextMenu: (event: React.MouseEvent<HTMLElement>, item: any) => void;
+ onContextMenu?: (event: React.MouseEvent<HTMLElement>, item: any) => void;
onRowDoubleClick: (item: any) => void;
extractKey?: (item: any) => React.Key;
}
<AccountMenu />
<HelpMenu />
</>
- : <AnonymousMenu />}
+ : <HelpMenu />}
</Grid>
</Grid>
</Toolbar>
buttonVisible: boolean;
}
-const isButtonVisible = ({ router }: RootState) => {
+const isWorkflowPath = ({ router }: RootState) => {
const pathname = router.location ? router.location.pathname : '';
- const match = !matchWorkflowRoute(pathname);
+ const match = matchWorkflowRoute(pathname);
return !!match;
};
export const MainContentBar = connect((state: RootState) => ({
- buttonVisible: isButtonVisible(state)
+ buttonVisible: !isWorkflowPath(state)
}), {
onDetailsPanelToggle: detailsPanelActions.TOGGLE_DETAILS_PANEL
})((props: MainContentBarProps) =>
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { compose } from 'redux';
+import { connect, DispatchProp } from 'react-redux';
+import { Grid, Typography, Button } from '@material-ui/core';
+import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
+import { login } from '~/store/auth/auth-action';
+import { ArvadosTheme } from '~/common/custom-theme';
+import * as classNames from 'classnames';
+
+type CssRules = 'root' | 'container' | 'title' | 'content' | 'content__bolder' | 'button';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ root: {
+ position: 'relative',
+ backgroundColor: theme.palette.grey["200"],
+ '&::after': {
+ content: `''`,
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ bottom: 0,
+ right: 0,
+ background: 'url("arvados-logo-big.png") no-repeat center center',
+ opacity: 0.2,
+ }
+ },
+ container: {
+ width: '560px',
+ zIndex: 10
+ },
+ title: {
+ marginBottom: theme.spacing.unit * 6,
+ color: theme.palette.grey["800"]
+ },
+ content: {
+ marginBottom: theme.spacing.unit * 3,
+ lineHeight: '1.2rem',
+ color: theme.palette.grey["800"]
+ },
+ 'content__bolder': {
+ fontWeight: 'bolder'
+ },
+ button: {
+ boxShadow: 'none'
+ }
+});
+
+type LoginPanelProps = DispatchProp<any> & WithStyles<CssRules>;
+
+export const LoginPanel = compose(
+ withStyles(styles),
+ connect()
+)(({ classes, dispatch }: LoginPanelProps) =>
+ <Grid container direction="column" item xs alignItems="center" justify="center" className={classes.root}>
+ <Grid item className={classes.container}>
+ <Typography variant="title" align="center" className={classes.title}>
+ Welcome to the Arvados Wrokbench
+ </Typography>
+ <Typography variant="body1" className={classes.content}>
+ The "Log in" button below will show you a Google sign-in page.
+ After you assure Google that you want to log in here with your Google account, you will be redirected back here to Arvados Workbench.
+ </Typography>
+ <Typography variant="body1" className={classes.content}>
+ If you have never used Arvados Workbench before, logging in for the first time will automatically create a new account.
+ </Typography>
+ <Typography variant="body2" className={classNames(classes.content, classes.content__bolder)}>
+ IMPORTANT: Please keep in mind to store exploratory data only but not any information used for clinical decision making.
+ </Typography>
+ <Typography variant="body1" className={classes.content}>
+ Arvados Workbench uses your name and email address only for identification, and does not retrieve any other personal information from Google.
+ </Typography>
+ <Typography component="div" align="right">
+ <Button variant="contained" color="primary" className={classes.button} onClick={() => dispatch(login())}>
+ Log in
+ </Button>
+ </Typography>
+ </Grid>
+ </Grid>
+);
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { connect, DispatchProp } from 'react-redux';
+import { push } from 'react-router-redux';
+import { LinearProgress, Grid } from '@material-ui/core';
+import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { RootState } from '~/store/store';
+import { User } from '~/models/user';
+import { WorkbenchPanel } from '~/views/workbench/workbench';
+import { LoginPanel } from '~/views/login-panel/login-panel';
+import { MainAppBar } from '~/views-components/main-app-bar/main-app-bar';
+import { isSystemWorking } from '~/store/progress-indicator/progress-indicator-reducer';
+import { isWorkbenchLoading } from '../../store/workbench/workbench-actions';
+import { WorkbenchLoadingScreen } from '~/views/workbench/workbench-loading-screen';
+
+type CssRules = 'root';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ root: {
+ overflow: 'hidden',
+ width: '100vw',
+ height: '100vh'
+ }
+});
+
+interface MainPanelDataProps {
+ user?: User;
+ working: boolean;
+ loading: boolean;
+}
+
+interface MainPanelGeneralProps {
+ buildInfo: string;
+}
+
+interface MainPanelState {
+ searchText: string;
+}
+
+type MainPanelProps = MainPanelDataProps & MainPanelGeneralProps & DispatchProp<any> & WithStyles<CssRules>;
+
+export const MainPanel = withStyles(styles)(
+ connect<MainPanelDataProps>(
+ (state: RootState) => ({
+ user: state.auth.user,
+ working: isSystemWorking(state.progressIndicator),
+ loading: isWorkbenchLoading(state)
+ })
+ )(
+ class extends React.Component<MainPanelProps, MainPanelState> {
+ state = {
+ searchText: "",
+ };
+
+ render() {
+ const { classes, user, buildInfo, working, loading } = this.props;
+ const { searchText } = this.state;
+ return loading
+ ? <WorkbenchLoadingScreen />
+ : <>
+ <MainAppBar
+ searchText={searchText}
+ user={user}
+ onSearch={this.onSearch}
+ buildInfo={buildInfo}>
+ {working ? <LinearProgress color="secondary" /> : null}
+ </MainAppBar>
+ <Grid container direction="column" className={classes.root}>
+ {user ? <WorkbenchPanel /> : <LoginPanel />}
+ </Grid>
+ </>;
+ }
+
+ onSearch = (searchText: string) => {
+ this.setState({ searchText });
+ this.props.dispatch(push(`/search?q=${searchText}`));
+ }
+ }
+ )
+);
\ No newline at end of file
--- /dev/null
+// 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='/arvados_logo.png' className={classes.img} />
+ <CircularProgress />
+ </Grid>
+);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
-import { Workbench } from './workbench';
+import { WorkbenchPanel } from './workbench';
import { Provider } from "react-redux";
import { configureStore } from "~/store/store";
import createBrowserHistory from "history/createBrowserHistory";
<MuiThemeProvider theme={CustomTheme}>
<Provider store={store}>
<ConnectedRouter history={history}>
- <Workbench authService={services.authService}/>
+ <WorkbenchPanel />
</ConnectedRouter>
</Provider>
</MuiThemeProvider>,
import * as React from 'react';
import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
-import { connect, DispatchProp } from "react-redux";
import { Route, Switch } from "react-router";
-import { User } from "~/models/user";
-import { RootState } from "~/store/store";
-import { MainAppBar } from '~/views-components/main-app-bar/main-app-bar';
-import { push } from 'react-router-redux';
import { ProjectPanel } from "~/views/project-panel/project-panel";
import { DetailsPanel } from '~/views-components/details-panel/details-panel';
import { ArvadosTheme } from '~/common/custom-theme';
-import { detailsPanelActions } from "~/store/details-panel/details-panel-action";
import { ContextMenu } from "~/views-components/context-menu/context-menu";
import { FavoritePanel } from "../favorite-panel/favorite-panel";
import { CurrentTokenDialog } from '~/views-components/current-token-dialog/current-token-dialog';
import { Snackbar } from '~/views-components/snackbar/snackbar';
import { CollectionPanel } from '../collection-panel/collection-panel';
-import { AuthService } from "~/services/auth-service/auth-service";
import { RenameFileDialog } from '~/views-components/rename-file-dialog/rename-file-dialog';
import { FileRemoveDialog } from '~/views-components/file-remove-dialog/file-remove-dialog';
import { MultipleFilesRemoveDialog } from '~/views-components/file-remove-dialog/multiple-files-remove-dialog';
import { PartialCopyCollectionDialog } from '~/views-components/dialog-forms/partial-copy-collection-dialog';
import { TrashPanel } from "~/views/trash-panel/trash-panel";
import { MainContentBar } from '~/views-components/main-content-bar/main-content-bar';
-import { Grid, LinearProgress } from '@material-ui/core';
+import { Grid } from '@material-ui/core';
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 { WorkflowPanel } from '~/views/workflow-panel/workflow-panel';
-type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content' | 'appBar';
+type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
root: {
- overflow: 'hidden',
- width: '100vw',
- height: '100vh',
- paddingTop: theme.spacing.unit * 8
+ paddingTop: theme.spacing.unit * 7,
+ background: theme.palette.background.default
},
container: {
position: 'relative'
}
},
asidePanel: {
- height: '100%',
- background: theme.palette.background.default
+ paddingTop: theme.spacing.unit,
+ height: '100%'
},
contentWrapper: {
- background: theme.palette.background.default,
- minWidth: 0,
+ paddingTop: theme.spacing.unit,
+ minWidth: 0
},
content: {
minWidth: 0,
paddingLeft: theme.spacing.unit * 3,
paddingRight: theme.spacing.unit * 3,
- },
- appBar: {
- zIndex: 1,
}
});
-interface WorkbenchDataProps {
- user?: User;
- currentToken?: string;
- working: boolean;
-}
-
-interface WorkbenchGeneralProps {
- authService: AuthService;
- buildInfo: string;
-}
-
-type WorkbenchProps = WorkbenchDataProps & WorkbenchGeneralProps & DispatchProp<any> & WithStyles<CssRules>;
+type WorkbenchPanelProps = WithStyles<CssRules>;
-interface WorkbenchState {
- searchText: string;
-}
-
-export const Workbench = withStyles(styles)(
- connect<WorkbenchDataProps>(
- (state: RootState) => ({
- user: state.auth.user,
- currentToken: state.auth.apiToken,
- working: isSystemWorking(state.progressIndicator)
- })
- )(
- class extends React.Component<WorkbenchProps, WorkbenchState> {
- state = {
- 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 />
- </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} />
- <Route path={Routes.WORKFLOWS} component={WorkflowPanel} />
- </Switch>
- </Grid>
- </Grid>
- </SplitterLayout>
- </Grid>
- <Grid item>
- <DetailsPanel />
- </Grid>
- </Grid>
- }
+export const WorkbenchPanel =
+ withStyles(styles)(({ classes }: WorkbenchPanelProps) =>
+ <Grid container item xs className={classes.root}>
+ <Grid container item xs 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>
- <ContextMenu />
- <CopyCollectionDialog />
- <CopyProcessDialog />
- <CreateCollectionDialog />
- <CreateProjectDialog />
- <CurrentTokenDialog />
- <FileRemoveDialog />
- <FileRemoveDialog />
- <FilesUploadCollectionDialog />
- <MoveCollectionDialog />
- <MoveProcessDialog />
- <MoveProjectDialog />
- <MultipleFilesRemoveDialog />
- <PartialCopyCollectionDialog />
- <ProcessCommandDialog />
- <RenameFileDialog />
- <Snackbar />
- <UpdateCollectionDialog />
- <UpdateProcessDialog />
- <UpdateProjectDialog />
- </>;
- }
-
- onSearch = (searchText: string) => {
- this.setState({ searchText });
- this.props.dispatch(push(`/search?q=${searchText}`));
- }
-
- toggleDetailsPanel = () => {
- this.props.dispatch(detailsPanelActions.TOGGLE_DETAILS_PANEL());
- }
-
- }
- )
-);
+ <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} />
+ <Route path={Routes.WORKFLOWS} component={WorkflowPanel} />
+ </Switch>
+ </Grid>
+ </Grid>
+ </SplitterLayout>
+ </Grid>
+ <Grid item>
+ <DetailsPanel />
+ </Grid>
+ <ContextMenu />
+ <CopyCollectionDialog />
+ <CopyProcessDialog />
+ <CreateCollectionDialog />
+ <CreateProjectDialog />
+ <CurrentTokenDialog />
+ <FileRemoveDialog />
+ <FileRemoveDialog />
+ <FilesUploadCollectionDialog />
+ <MoveCollectionDialog />
+ <MoveProcessDialog />
+ <MoveProjectDialog />
+ <MultipleFilesRemoveDialog />
+ <PartialCopyCollectionDialog />
+ <ProcessCommandDialog />
+ <RenameFileDialog />
+ <Snackbar />
+ <UpdateCollectionDialog />
+ <UpdateProcessDialog />
+ <UpdateProjectDialog />
+ </Grid>
+ );
// SPDX-License-Identifier: AGPL-3.0
import * as React from 'react';
-import { StyleRulesCallback, WithStyles, withStyles, Card, CardHeader, Typography } from '@material-ui/core';
+import { StyleRulesCallback, WithStyles, withStyles, Card, CardHeader, Typography, CardContent } from '@material-ui/core';
import { ArvadosTheme } from '~/common/custom-theme';
import { WorkflowIcon } from '~/components/icon/icon';
import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
title={<Typography noWrap variant="body2">
Workflow description:
</Typography>} />
- <DataTableDefaultView
- icon={WorkflowIcon}
- messages={['Please select a workflow to see its description.']} />
+ <CardContent>
+ <DataTableDefaultView
+ icon={WorkflowIcon}
+ messages={['Please select a workflow to see its description.']} />
+ </CardContent>
</Card>;
});
\ No newline at end of file
selected: true,
}
],
+ // do zmiany na ResourceAuthorisation
render: (uuid: string) => <ResourceName uuid={uuid} />,
},
{
}))(
class extends React.Component<WorkflowPanelProps> {
render() {
- return <Grid container>
- <Grid item xs={6} style={{ paddingRight: '24px', display: 'grid' }}>
+ return <Grid container spacing={16}>
+ <Grid item xs={6}>
<DataExplorer
id={WORKFLOW_PANEL_ID}
onRowClick={this.handleRowClick}