Create collection input
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Thu, 11 Oct 2018 18:56:32 +0000 (20:56 +0200)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Thu, 11 Oct 2018 18:56:32 +0000 (20:56 +0200)
Feature #13862

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

src/views/run-process-panel/inputs/directory-input.tsx [new file with mode: 0644]
src/views/run-process-panel/run-process-inputs-form.tsx

diff --git a/src/views/run-process-panel/inputs/directory-input.tsx b/src/views/run-process-panel/inputs/directory-input.tsx
new file mode 100644 (file)
index 0000000..c0e21e8
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import {
+    isRequiredInput,
+    DirectoryCommandInputParameter,
+    CWLType,
+    Directory
+} from '~/models/workflow';
+import { Field } from 'redux-form';
+import { require } from '~/validators/require';
+import { Input, Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@material-ui/core';
+import { GenericInputProps, GenericInput } from './generic-input';
+import { ProjectsTreePicker } from '~/views-components/projects-tree-picker/projects-tree-picker';
+import { connect, DispatchProp } from 'react-redux';
+import { initProjectsTreePicker } from '~/store/tree-picker/tree-picker-actions';
+import { TreeItem } from '~/components/tree/tree';
+import { ProjectsTreePickerItem } from '~/views-components/projects-tree-picker/generic-projects-tree-picker';
+import { CollectionResource } from '~/models/collection';
+import { ResourceKind } from '~/models/resource';
+
+export interface DirectoryInputProps {
+    input: DirectoryCommandInputParameter;
+}
+export const DirectoryInput = ({ input }: DirectoryInputProps) =>
+    <Field
+        name={input.id}
+        commandInput={input}
+        component={DirectoryInputComponent}
+        format={(value?: Directory) => value ? value.basename : ''}
+        parse={(directory: CollectionResource): Directory => ({
+            class: CWLType.DIRECTORY,
+            location: `keep:${directory.portableDataHash}`,
+            basename: directory.name,
+        })}
+        validate={[
+            isRequiredInput(input)
+                ? require
+                : () => undefined,
+        ]} />;
+
+
+interface DirectoryInputComponentState {
+    open: boolean;
+    directory?: CollectionResource;
+}
+
+const DirectoryInputComponent = connect()(
+    class FileInputComponent extends React.Component<GenericInputProps & DispatchProp, DirectoryInputComponentState> {
+        state: DirectoryInputComponentState = {
+            open: false,
+        };
+
+        componentDidMount() {
+            this.props.dispatch<any>(
+                initProjectsTreePicker(this.props.commandInput.id));
+        }
+
+        render() {
+            return <>
+                {this.renderInput()}
+                {this.renderDialog()}
+            </>;
+        }
+
+        openDialog = () => {
+            this.setState({ open: true });
+        }
+
+        closeDialog = () => {
+            this.setState({ open: false });
+        }
+
+        submit = () => {
+            this.closeDialog();
+            this.props.input.onChange(this.state.directory);
+        }
+
+        setDirectory = (event: React.MouseEvent<HTMLElement>, { data }: TreeItem<ProjectsTreePickerItem>, pickerId: string) => {
+            if ('kind' in data && data.kind === ResourceKind.COLLECTION) {
+                this.setState({ directory: data });
+            } else {
+                this.setState({ directory: undefined });
+            }
+        }
+
+        renderInput() {
+            return <GenericInput
+                component={props =>
+                    <Input
+                        readOnly
+                        fullWidth
+                        value={props.input.value}
+                        error={props.meta.touched && !!props.meta.error}
+                        onClick={this.openDialog}
+                        onKeyPress={this.openDialog} />}
+                {...this.props} />;
+        }
+
+        renderDialog() {
+            return <Dialog
+                open={this.state.open}
+                onClose={this.closeDialog}
+                fullWidth
+                maxWidth='md'>
+                <DialogTitle>Choose a directory</DialogTitle>
+                <DialogContent>
+                    <ProjectsTreePicker
+                        pickerId={this.props.commandInput.id}
+                        includeCollections
+                        toggleItemActive={this.setDirectory} />
+                </DialogContent>
+                <DialogActions>
+                    <Button onClick={this.closeDialog}>Cancel</Button>
+                    <Button
+                        disabled={!this.state.directory}
+                        variant='contained'
+                        color='primary'
+                        onClick={this.submit}>Ok</Button>
+                </DialogActions>
+            </Dialog>;
+        }
+
+    });
+
+
index b0d5d5fefb4505537a1322e1be47f6332aa01033..41355b2ab9c8da07dc30fc368ee23d21b1a1cc5b 100644 (file)
@@ -4,7 +4,7 @@
 
 import * as React from 'react';
 import { reduxForm, InjectedFormProps } from 'redux-form';
-import { CommandInputParameter, CWLType, IntCommandInputParameter, BooleanCommandInputParameter, FileCommandInputParameter } from '~/models/workflow';
+import { CommandInputParameter, CWLType, IntCommandInputParameter, BooleanCommandInputParameter, FileCommandInputParameter, DirectoryCommandInputParameter } from '~/models/workflow';
 import { IntInput } from '~/views/run-process-panel/inputs/int-input';
 import { StringInput } from '~/views/run-process-panel/inputs/string-input';
 import { StringCommandInputParameter, FloatCommandInputParameter, isPrimitiveOfType, File, Directory, WorkflowInputsData, EnumCommandInputParameter } from '../../models/workflow';
@@ -15,6 +15,7 @@ import { connect } from 'react-redux';
 import { compose } from 'redux';
 import { Grid, StyleRulesCallback, withStyles, WithStyles } from '@material-ui/core';
 import { EnumInput } from './inputs/enum-input';
+import { DirectoryInput } from './inputs/directory-input';
 
 export const RUN_PROCESS_INPUTS_FORM = 'runProcessInputsForm';
 
@@ -71,6 +72,9 @@ const getInputComponent = (input: CommandInputParameter) => {
 
         case isPrimitiveOfType(input, CWLType.FILE):
             return <FileInput input={input as FileCommandInputParameter} />;
+        
+        case isPrimitiveOfType(input, CWLType.DIRECTORY):
+            return <DirectoryInput input={input as DirectoryCommandInputParameter} />;
 
         case typeof input.type === 'object' &&
             !(input.type instanceof Array) &&