Merge branch 'master' into 14099-process-service
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Wed, 29 Aug 2018 14:18:28 +0000 (16:18 +0200)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Wed, 29 Aug 2018 14:18:28 +0000 (16:18 +0200)
refs #14099

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

12 files changed:
src/components/details-attribute/details-attribute.tsx
src/index.tsx
src/routes/routes.ts
src/store/context-menu/context-menu-actions.ts
src/views-components/context-menu/action-sets/process-action-set.ts [new file with mode: 0644]
src/views-components/context-menu/context-menu.tsx
src/views-components/dialog-create/dialog-collection-create-selected.tsx [deleted file]
src/views-components/process-information-card/process-information-card.ts [new file with mode: 0644]
src/views-components/rename-file-dialog/rename-file-dialog.tsx
src/views/process-panel/process-information-card.tsx [new file with mode: 0644]
src/views/process-panel/process-panel.tsx [new file with mode: 0644]
src/views/workbench/workbench.tsx

index 71778859564b6f2ab1c04c3fd97efc29bd073665..fd8e948ff046a5c14106e16ea426ff31b3807d4f 100644 (file)
@@ -33,7 +33,8 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         width: '60%',
         color: theme.palette.primary.main,
         textDecoration: 'none',
-        overflowWrap: 'break-word'
+        overflowWrap: 'break-word',
+        cursor: 'pointer'
     }
 });
 
index c7f76c68f8c2e971a7558122f50ba0602512fea9..d3115a6754bf70feb6731e8910e71b04859534f4 100644 (file)
@@ -27,6 +27,7 @@ import { collectionFilesActionSet } from './views-components/context-menu/action
 import { collectionFilesItemActionSet } from './views-components/context-menu/action-sets/collection-files-item-action-set';
 import { collectionActionSet } from './views-components/context-menu/action-sets/collection-action-set';
 import { collectionResourceActionSet } from './views-components/context-menu/action-sets/collection-resource-action-set';
+import { processActionSet } from './views-components/context-menu/action-sets/process-action-set';
 import { addRouteChangeHandlers } from './routes/routes';
 import { loadWorkbench } from './store/workbench/workbench-actions';
 import { Routes } from '~/routes/routes';
@@ -47,6 +48,7 @@ addMenuActionSet(ContextMenuKind.COLLECTION_FILES, collectionFilesActionSet);
 addMenuActionSet(ContextMenuKind.COLLECTION_FILES_ITEM, collectionFilesItemActionSet);
 addMenuActionSet(ContextMenuKind.COLLECTION, collectionActionSet);
 addMenuActionSet(ContextMenuKind.COLLECTION_RESOURCE, collectionResourceActionSet);
+addMenuActionSet(ContextMenuKind.PROCESS, processActionSet);
 
 fetchConfig()
     .then((config) => {
index 0279bb06f25f0a2372a848f7cc7cbb9585fcd36c..0bf7110126df7849f4571cfbe6e2c21dffa49fdd 100644 (file)
@@ -15,6 +15,7 @@ export const Routes = {
     TOKEN: '/token',
     PROJECTS: `/projects/:id(${RESOURCE_UUID_PATTERN})`,
     COLLECTIONS: `/collections/:id(${RESOURCE_UUID_PATTERN})`,
+    PROCESS: `/processes/:id(${RESOURCE_UUID_PATTERN})`,
     FAVORITES: '/favorites',
 };
 
index 406239997c68d01905644d47dc5b12299fb95aeb..cf66a53d2361587823219d3d698cfa2572fd07d5 100644 (file)
@@ -67,6 +67,17 @@ export const openSidePanelContextMenu = (event: React.MouseEvent<HTMLElement>, i
         }
     };
 
+export const openProcessContextMenu = (event: React.MouseEvent<HTMLElement>) =>
+    (dispatch: Dispatch, getState: () => RootState) => {
+        const resource = {
+            uuid: '',
+            name: '',
+            description: '',
+            kind: ContextMenuKind.PROCESS
+        };
+        dispatch<any>(openContextMenu(event, resource));
+    };
+
 export const resourceKindToContextMenuKind = (uuid: string) => {
     const kind = extractUuidKind(uuid);
     switch (kind) {
diff --git a/src/views-components/context-menu/action-sets/process-action-set.ts b/src/views-components/context-menu/action-sets/process-action-set.ts
new file mode 100644 (file)
index 0000000..5d679f5
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ContextMenuActionSet } from "../context-menu-action-set";
+import { ToggleFavoriteAction } from "../actions/favorite-action";
+import { toggleFavorite } from "~/store/favorites/favorites-actions";
+import {
+    RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, ProvenanceGraphIcon,
+    AdvancedIcon, RemoveIcon, ReRunProcessIcon, LogIcon
+} from "~/components/icon/icon";
+import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
+
+export const processActionSet: ContextMenuActionSet = [[
+    {
+        icon: RenameIcon,
+        name: "Edit process",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: ShareIcon,
+        name: "Share",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: MoveToIcon,
+        name: "Move to",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        component: ToggleFavoriteAction,
+        execute: (dispatch, resource) => {
+            dispatch<any>(toggleFavorite(resource)).then(() => {
+                dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
+            });
+        }
+    },
+    {
+        icon: CopyIcon,
+        name: "Copy to project",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: ReRunProcessIcon,
+        name: "Re-run process",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        name: "Inputs",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        name: "Outputs",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        name: "Command",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: DetailsIcon,
+        name: "View details",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: LogIcon,
+        name: "Log",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: ProvenanceGraphIcon,
+        name: "Provenance graph",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: AdvancedIcon,
+        name: "Advanced",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: RemoveIcon,
+        name: "Remove",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    }
+]];
index 8036bb572859ee90a11fa94474a328ec69aca07f..5d94766c447674170560e45b5392993ef505a977 100644 (file)
@@ -63,5 +63,6 @@ export enum ContextMenuKind {
     COLLECTION_FILES = "CollectionFiles",
     COLLECTION_FILES_ITEM = "CollectionFilesItem",
     COLLECTION = 'Collection',
-    COLLECTION_RESOURCE = 'CollectionResource'
+    COLLECTION_RESOURCE = 'CollectionResource',
+    PROCESS = "Process"
 }
diff --git a/src/views-components/dialog-create/dialog-collection-create-selected.tsx b/src/views-components/dialog-create/dialog-collection-create-selected.tsx
deleted file mode 100644 (file)
index ad684d7..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import * as React from "react";
-import { InjectedFormProps, Field, WrappedFieldProps } from "redux-form";
-import { Dialog, DialogTitle, DialogContent, DialogActions, Button, CircularProgress } from "@material-ui/core";
-import { WithDialogProps } from "~/store/dialog/with-dialog";
-import { TextField } from "~/components/text-field/text-field";
-import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION, COLLECTION_PROJECT_VALIDATION } from "~/validators/validators";
-import { ProjectTreePicker } from "../project-tree-picker/project-tree-picker";
-
-export const DialogCollectionCreateWithSelected = (props: WithDialogProps<string> & InjectedFormProps<{ name: string }>) =>
-    <form>
-        <Dialog open={props.open}
-            disableBackdropClick={true}
-            disableEscapeKeyDown={true}>
-            <DialogTitle>Create a collection</DialogTitle>
-            <DialogContent style={{ display: 'flex' }}>
-                <div>
-                    <Field
-                        name='name'
-                        component={TextField}
-                        validate={COLLECTION_NAME_VALIDATION}
-                        label="Collection Name" />
-                    <Field
-                        name='description'
-                        component={TextField}
-                        validate={COLLECTION_DESCRIPTION_VALIDATION}
-                        label="Description - optional" />
-                </div>
-                <Field
-                    name="projectUuid"
-                    component={Picker}
-                    validate={COLLECTION_PROJECT_VALIDATION} />
-            </DialogContent>
-            <DialogActions>
-                <Button
-                    variant='flat'
-                    color='primary'
-                    disabled={props.submitting}
-                    onClick={props.closeDialog}>
-                    Cancel
-                    </Button>
-                <Button
-                    variant='contained'
-                    color='primary'
-                    type='submit'
-                    onClick={props.handleSubmit}
-                    disabled={props.pristine || props.invalid || props.submitting}>
-                    {props.submitting ? <CircularProgress size={20} /> : 'Create a collection'}
-                </Button>
-            </DialogActions>
-        </Dialog>
-    </form>;
-
-const Picker = (props: WrappedFieldProps) =>
-    <div style={{ width: '400px', height: '144px', display: 'flex', flexDirection: 'column' }}>
-        <ProjectTreePicker onChange={projectUuid => props.input.onChange(projectUuid)} />
-    </div>;
diff --git a/src/views-components/process-information-card/process-information-card.ts b/src/views-components/process-information-card/process-information-card.ts
new file mode 100644 (file)
index 0000000..bf9172d
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch } from 'redux';
+import { openProcessContextMenu } from '~/store/context-menu/context-menu-actions';
+import { connect } from 'react-redux';
+import { RootState } from '~/store/store';
+import { ProcessInformationCard as InformationCardComponent, ProcessInformationCardDataProps } from '~/views/process-panel/process-information-card';
+
+type InformationCardActionProps = Pick<ProcessInformationCardDataProps, 'onContextMenu'>;
+
+const mapStateToProps = (state: RootState) => ({
+    // todo: change for processPanel
+    item: state.collectionPanel.item
+});
+
+const mapDispatchToProps = (dispatch: Dispatch): InformationCardActionProps => ({
+    onContextMenu: (event: React.MouseEvent<HTMLElement>) => {
+        dispatch<any>(openProcessContextMenu(event));
+    }
+});
+
+export const ProcessInformationCard = connect(mapStateToProps, mapDispatchToProps)(InformationCardComponent);
\ No newline at end of file
index 20116fcda747c0f322223b48fc6d83b67a024762..862227bd888c27c277e4b4d9e28d66a0e36b76f3 100644 (file)
@@ -4,7 +4,7 @@
 
 import * as React from 'react';
 import { compose } from 'redux';
-import { reduxForm, reset, startSubmit, stopSubmit, InjectedFormProps, Field } from 'redux-form';
+import { reduxForm, InjectedFormProps, Field } from 'redux-form';
 import { withDialog, WithDialogProps } from '~/store/dialog/with-dialog';
 import { FormDialog } from '~/components/form-dialog/form-dialog';
 import { DialogContentText } from '@material-ui/core';
diff --git a/src/views/process-panel/process-information-card.tsx b/src/views/process-panel/process-information-card.tsx
new file mode 100644 (file)
index 0000000..a50490c
--- /dev/null
@@ -0,0 +1,119 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import {
+    StyleRulesCallback, WithStyles, withStyles, Card,
+    CardHeader, IconButton, CardContent, Grid, Chip, Typography, Tooltip
+} from '@material-ui/core';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { MoreOptionsIcon, ProcessIcon } from '~/components/icon/icon';
+import { DetailsAttribute } from '~/components/details-attribute/details-attribute';
+
+type CssRules = 'card' | 'iconHeader' | 'label' | 'value' | 'chip' | 'headerText' | 'link' | 'content' | 'title' | 'avatar';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+    card: {
+        marginBottom: theme.spacing.unit * 2
+    },
+    iconHeader: {
+        fontSize: '1.875rem',
+        color: theme.customs.colors.green700,
+    },
+    avatar: {
+        alignSelf: 'flex-start'
+    },
+    label: {
+        display: 'flex',
+        justifyContent: 'flex-end',
+        fontSize: '0.875rem',
+        marginRight: theme.spacing.unit * 3,
+        paddingRight: theme.spacing.unit
+    },
+    value: {
+        textTransform: 'none',
+        fontSize: '0.875rem',
+    },
+    link: {
+        fontSize: '0.875rem',
+        color: theme.palette.primary.main,
+        '&:hover': {
+            cursor: 'pointer'
+        }
+    },
+    chip: {
+        height: theme.spacing.unit * 3,
+        width: theme.spacing.unit * 12,
+        backgroundColor: theme.customs.colors.green700,
+        color: theme.palette.common.white,
+        fontSize: '0.875rem',
+        borderRadius: theme.spacing.unit * 0.625,
+    },
+    headerText: {
+        fontSize: '0.875rem',
+        marginLeft: theme.spacing.unit * 3,
+    },
+    content: {
+        '&:last-child': {
+            paddingBottom: theme.spacing.unit * 2,
+            paddingTop: '0px'
+        }
+    },
+    title: {
+        overflow: 'hidden'
+    }
+});
+
+export interface ProcessInformationCardDataProps {
+    item: any;
+    onContextMenu: (event: React.MouseEvent<HTMLElement>) => void;
+}
+
+type ProcessInformationCardProps = ProcessInformationCardDataProps & WithStyles<CssRules>;
+
+export const ProcessInformationCard = withStyles(styles)(
+    ({ classes, onContextMenu }: ProcessInformationCardProps) =>
+        <Card className={classes.card}>
+            <CardHeader
+                classes={{
+                    content: classes.title,
+                    avatar: classes.avatar
+                }}
+                avatar={<ProcessIcon className={classes.iconHeader} />}
+                action={
+                    <div>
+                        <Chip label="Complete" className={classes.chip} />
+                        <IconButton
+                            aria-label="More options"
+                            onClick={event => onContextMenu(event)}>
+                            <MoreOptionsIcon />
+                        </IconButton>
+                    </div>
+                }
+                title={
+                    <Tooltip title="Pipeline template that generates a config file from a template">
+                        <Typography noWrap variant="title">
+                            Pipeline template that generates a config file from a template
+                        </Typography>
+                    </Tooltip>
+                }
+                subheader="(no-description)" />
+            <CardContent className={classes.content}>
+                <Grid container>
+                    <Grid item xs={6}>
+                        <DetailsAttribute classLabel={classes.label} classValue={classes.value}
+                            label='From' value="1:25 PM 3/23/2018" />
+                        <DetailsAttribute classLabel={classes.label} classValue={classes.value}
+                            label='To' value='1:25 PM 3/23/2018' />
+                        <DetailsAttribute classLabel={classes.label} classValue={classes.link}
+                            label='Workflow' value='FastQC MultiQC' />
+                    </Grid>
+                    <Grid item xs={6}>
+                        <DetailsAttribute classLabel={classes.link} label='Outputs' />
+                        <DetailsAttribute classLabel={classes.link} label='Inputs' />
+                    </Grid>
+                </Grid>
+            </CardContent>
+        </Card>
+);
\ No newline at end of file
diff --git a/src/views/process-panel/process-panel.tsx b/src/views/process-panel/process-panel.tsx
new file mode 100644 (file)
index 0000000..f416f7b
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { ProcessInformationCard } from '~/views-components/process-information-card/process-information-card';
+import { Grid } from '@material-ui/core';
+
+export class ProcessPanel extends React.Component {
+    render() {
+        return <div>
+            <Grid container>
+                <Grid item xs={7}>
+                    <ProcessInformationCard />
+                </Grid>
+            </Grid>
+        </div>;
+    }
+}
\ No newline at end of file
index 82a868e6dece3fb472d53d11b1fa99fa8c20461d..1d53842b422bcbcb4484b6607c355d46fa5d8445 100644 (file)
@@ -34,6 +34,7 @@ import { UpdateCollectionDialog } from '~/views-components/dialog-forms/update-c
 import { UpdateProjectDialog } from '~/views-components/dialog-forms/update-project-dialog';
 import { MoveProjectDialog } from '~/views-components/dialog-forms/move-project-dialog';
 import { MoveCollectionDialog } from '~/views-components/dialog-forms/move-collection-dialog';
+import { ProcessPanel } from '~/views/process-panel/process-panel';
 import { UploadCollectionFilesDialog } from '~/views-components/dialog-forms/upload-collection-files-dialog';
 import { PartialCopyCollectionDialog } from '~/views-components/dialog-forms/partial-copy-collection-dialog';
 
@@ -165,6 +166,7 @@ export const Workbench = withStyles(styles)(
                                     <Route path={Routes.PROJECTS} component={ProjectPanel} />
                                     <Route path={Routes.COLLECTIONS} component={CollectionPanel} />
                                     <Route path={Routes.FAVORITES} component={FavoritePanel} />
+                                    <Route path={Routes.PROCESS} component={ProcessPanel} />
                                 </Switch>
                             </div>
                             {user && <DetailsPanel />}