airavata-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From machris...@apache.org
Subject [airavata-django-portal] 13/28: AIRAVATA-2876 Adding new application input
Date Tue, 11 Sep 2018 17:12:01 GMT
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit e441f97c7a53ff5b11df5194bc66f5104bf69517
Author: Marcus Christie <machrist@iu.edu>
AuthorDate: Tue Sep 4 16:00:52 2018 -0400

    AIRAVATA-2876 Adding new application input
---
 .../applications/ApplicationInputFieldEditor.vue   |  15 +-
 .../applications/ApplicationInterfaceEditor.vue    |  18 +-
 .../api/static/django_airavata_api/js/index.js     |   1 -
 .../js/models/ApplicationInterfaceDefinition.js    |   7 -
 .../django_airavata_api/js/models/Experiment.js    | 194 ++++++++--------
 .../js/models/InputDataObjectType.js               | 247 +++++++++++----------
 6 files changed, 262 insertions(+), 220 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInputFieldEditor.vue
b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInputFieldEditor.vue
index 085fa8b..65cd2a8 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInputFieldEditor.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInputFieldEditor.vue
@@ -1,7 +1,7 @@
 <template>
   <b-card header="Input Field">
     <b-form-group label="Name" :label-for="id+'-name'">
-      <b-form-input :id="id+'-name'" type="text" v-model="data.name" required></b-form-input>
+      <b-form-input :id="id+'-name'" type="text" v-model="data.name" ref="nameInput" required></b-form-input>
     </b-form-group>
     <b-form-group label="Initial Value" :label-for="id+'-value'">
       <b-form-input :id="id+'-value'" type="text" v-model="data.value"></b-form-input>
@@ -55,6 +55,10 @@ export default {
     },
     id: {
       required: true
+    },
+    // Whether to put focus on the name field when mounting component
+    focus: {
+      type: Boolean
     }
   },
   computed: {
@@ -73,6 +77,15 @@ export default {
   methods: {
     copyValue() {
       return this.value.clone();
+    },
+    doFocus() {
+      this.$refs.nameInput.focus();
+      this.$el.scrollIntoView();
+    }
+  },
+  mounted() {
+    if (this.focus) {
+      this.doFocus();
     }
   }
 };
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInterfaceEditor.vue
b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInterfaceEditor.vue
index be490ba..00af581 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInterfaceEditor.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationInterfaceEditor.vue
@@ -26,7 +26,14 @@
         <h1 class="h5 mb-4">
           Input Fields
         </h1>
-        <application-input-field-editor v-for="(input, index) in data.applicationInputs"
:value="input" :key="index" :id="'app-input-'+index" @input="updatedInput($event, index)"
/>
+        <application-input-field-editor v-for="(input, index) in data.applicationInputs"
:value="input" :key="index" :id="'app-input-'+index" :focus="index === focusApplicationInputIndex"
@input="updatedInput($event, index)" />
+      </div>
+    </div>
+    <div class="row">
+      <div class="col">
+        <b-button variant="secondary" @click="addApplicationInput">
+          Add application input
+        </b-button>
       </div>
     </div>
     <div class="row">
@@ -63,6 +70,11 @@ export default {
       return [{ text: "True", value: true }, { text: "False", value: false }];
     }
   },
+  data() {
+    return {
+      focusApplicationInputIndex: null
+    };
+  },
   methods: {
     save() {
       this.$emit("save");
@@ -73,6 +85,10 @@ export default {
     updatedInput(newValue, index) {
       Object.assign(this.data.applicationInputs[index], newValue);
       this.$emit("input", this.data);
+    },
+    addApplicationInput() {
+      this.data.applicationInputs.push(new models.InputDataObjectType());
+      this.focusApplicationInputIndex = this.data.applicationInputs.length - 1;
     }
   }
 };
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/index.js b/django_airavata/apps/api/static/django_airavata_api/js/index.js
index 3d00054..ecb1e59 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/index.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/index.js
@@ -25,7 +25,6 @@ import SummaryType from './models/SummaryType'
 import UserPermission from './models/UserPermission'
 
 import ApplicationDeploymentService from './services/ApplicationDeploymentService'
-import ApplicationInterfaceService from './services/ApplicationInterfaceService'
 import ExperimentService from './services/ExperimentService'
 import ExperimentSearchService from './services/ExperimentSearchService'
 import FullExperimentService from './services/FullExperimentService'
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
b/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
index 801ec52..43c3ba6 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
@@ -41,12 +41,5 @@ export default class ApplicationInterfaceDefinition extends BaseModel {
 
   constructor(data = {}) {
     super(FIELDS, data);
-    // Order application inputs
-    this.applicationInputs = this.getOrderedApplicationInputs();
-  }
-
-  getOrderedApplicationInputs() {
-    // Use slice() to make a copy and sort that copy
-    return this.applicationInputs ? this.applicationInputs.slice().sort((a, b) => a.inputOrder
- b.inputOrder) : [];
   }
 }
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js b/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js
index a7f8304..47a49c4 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js
@@ -9,111 +9,111 @@ import ProcessModel from './ProcessModel'
 import UserConfigurationData from './UserConfigurationData'
 
 const FIELDS = [
-    'experimentId',
-    'projectId',
-    'gatewayId',
-    {
-        name: 'experimentType',
-        type: 'number',
-        default: 0,
-    },
-    'userName',
-    'experimentName',
-    {
-        name: 'creationTime',
-        type: 'date'
-    },
-    'description',
-    'executionId',
-    {
-        name: 'enableEmailNotification',
-        type: 'boolean',
-        default: false,
-    },
-    {
-        name: 'emailAddresses',
-        type: 'string',
-        list: true,
-    },
-    {
-        name: 'userConfigurationData',
-        type: UserConfigurationData,
-        default: BaseModel.defaultNewInstance(UserConfigurationData),
-    },
-    {
-        name: 'experimentInputs',
-        type: InputDataObjectType,
-        list: true,
-    },
-    {
-        name: 'experimentOutputs',
-        type: OutputDataObjectType,
-        list: true,
-    },
-    {
-        name: 'experimentStatus',
-        type: ExperimentStatus,
-        list: true,
-    },
-    {
-        name: 'errors',
-        type: ErrorModel,
-        list: true,
-    },
-    {
-        name: 'processes',
-        type: ProcessModel,
-        list: true,
-    },
+  'experimentId',
+  'projectId',
+  'gatewayId',
+  {
+    name: 'experimentType',
+    type: 'number',
+    default: 0,
+  },
+  'userName',
+  'experimentName',
+  {
+    name: 'creationTime',
+    type: 'date'
+  },
+  'description',
+  'executionId',
+  {
+    name: 'enableEmailNotification',
+    type: 'boolean',
+    default: false,
+  },
+  {
+    name: 'emailAddresses',
+    type: 'string',
+    list: true,
+  },
+  {
+    name: 'userConfigurationData',
+    type: UserConfigurationData,
+    default: BaseModel.defaultNewInstance(UserConfigurationData),
+  },
+  {
+    name: 'experimentInputs',
+    type: InputDataObjectType,
+    list: true,
+  },
+  {
+    name: 'experimentOutputs',
+    type: OutputDataObjectType,
+    list: true,
+  },
+  {
+    name: 'experimentStatus',
+    type: ExperimentStatus,
+    list: true,
+  },
+  {
+    name: 'errors',
+    type: ErrorModel,
+    list: true,
+  },
+  {
+    name: 'processes',
+    type: ProcessModel,
+    list: true,
+  },
 ];
 
 export default class Experiment extends BaseModel {
-    constructor(data = {}) {
-        super(FIELDS, data);
-    }
+  constructor(data = {}) {
+    super(FIELDS, data);
+  }
 
-    validate() {
-        let validationResults = {};
-        const userConfigurationDataValidation = this.userConfigurationData.validate();
-        if (Object.keys(userConfigurationDataValidation).length > 0) {
-            validationResults['userConfigurationData'] = userConfigurationDataValidation;
-        }
-        if (this.isEmpty(this.experimentName)) {
-            validationResults['experimentName'] = "Please provide a name for this experiment.";
-        }
-        if (this.isEmpty(this.projectId)) {
-            validationResults['projectId'] = "Please select a project.";
-        }
-        return validationResults;
+  validate() {
+    let validationResults = {};
+    const userConfigurationDataValidation = this.userConfigurationData.validate();
+    if (Object.keys(userConfigurationDataValidation).length > 0) {
+      validationResults['userConfigurationData'] = userConfigurationDataValidation;
     }
-
-    get latestStatus() {
-        if (this.experimentStatus && this.experimentStatus.length > 0) {
-            return this.experimentStatus[this.experimentStatus.length - 1];
-        } else {
-            return null;
-        }
+    if (this.isEmpty(this.experimentName)) {
+      validationResults['experimentName'] = "Please provide a name for this experiment.";
     }
-
-    get isProgressing() {
-        return this.latestStatus && this.latestStatus.isProgressing;
+    if (this.isEmpty(this.projectId)) {
+      validationResults['projectId'] = "Please select a project.";
     }
+    return validationResults;
+  }
 
-    get hasLaunched() {
-        const hasLaunchedStates = [ExperimentState.SCHEDULED,
-                                   ExperimentState.LAUNCHED,
-                                   ExperimentState.EXECUTING,
-                                   ExperimentState.CANCELING,
-                                   ExperimentState.CANCELED,
-                                   ExperimentState.FAILED,
-                                   ExperimentState.COMPLETED];
-        return this.latestStatus
-            && hasLaunchedStates.indexOf(this.latestStatus.state) >= 0;
+  get latestStatus() {
+    if (this.experimentStatus && this.experimentStatus.length > 0) {
+      return this.experimentStatus[this.experimentStatus.length - 1];
+    } else {
+      return null;
     }
+  }
 
-    populateInputsOutputsFromApplicationInterface(applicationInterface) {
-        // Copy application inputs and outputs to the experiment
-        this.experimentInputs = applicationInterface.getOrderedApplicationInputs().map(input
=> input.clone());
-        this.experimentOutputs = applicationInterface.applicationOutputs.slice();
-    }
+  get isProgressing() {
+    return this.latestStatus && this.latestStatus.isProgressing;
+  }
+
+  get hasLaunched() {
+    const hasLaunchedStates = [ExperimentState.SCHEDULED,
+    ExperimentState.LAUNCHED,
+    ExperimentState.EXECUTING,
+    ExperimentState.CANCELING,
+    ExperimentState.CANCELED,
+    ExperimentState.FAILED,
+    ExperimentState.COMPLETED];
+    return this.latestStatus
+      && hasLaunchedStates.indexOf(this.latestStatus.state) >= 0;
+  }
+
+  populateInputsOutputsFromApplicationInterface(applicationInterface) {
+    // Copy application inputs and outputs to the experiment
+    this.experimentInputs = applicationInterface.applicationInputs.map(input => input.clone());
+    this.experimentOutputs = applicationInterface.applicationOutputs.slice();
+  }
 }
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/InputDataObjectType.js
b/django_airavata/apps/api/static/django_airavata_api/js/models/InputDataObjectType.js
index 06cd623..83bb1c7 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/InputDataObjectType.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/InputDataObjectType.js
@@ -4,130 +4,151 @@ import DataType from './DataType';
 import ValidatorFactory from './validators/ValidatorFactory';
 
 const FIELDS = [
-    'name',
-    'value',
-    {
-        name: 'type',
-        type: DataType,
-    },
-    'applicationArgument',
-    'standardInput',
-    'userFriendlyDescription',
-    'metaData',
-    'inputOrder',
-    'isRequired',
-    'requiredToAddedToCommandLine',
-    'dataStaged',
-    'storageResourceId',
-    'isReadOnly',
+  'name',
+  'value',
+  {
+    name: 'type',
+    type: DataType,
+    default: DataType.STRING,
+  },
+  'applicationArgument',
+  {
+    name: 'standardInput',
+    type: 'boolean',
+    default: false,
+  },
+  'userFriendlyDescription',
+  'metaData',
+  'inputOrder',
+  {
+    name: 'isRequired',
+    type: 'boolean',
+    default: false,
+  },
+  {
+    name: 'requiredToAddedToCommandLine',
+    type: 'boolean',
+    default: false,
+  },
+  {
+    name: 'dataStaged',
+    type: 'boolean',
+    default: false,
+  },
+  'storageResourceId',
+  {
+    name: 'isReadOnly',
+    type: 'boolean',
+    default: false,
+  },
 ];
 
 export default class InputDataObjectType extends BaseModel {
-    constructor(data = {}) {
-        super(FIELDS, data);
-    }
+  constructor(data = {}) {
+    super(FIELDS, data);
+  }
 
-    /**
-     * Get the UI component id for the editor component to use for this input.
-     * Returns null if there is no editor UI component id.
-     *
-     * The expected JSON schema for the editor UI component id is the following:
-     * {
-     *   "editor": {
-     *     "ui-component-id": "input-editor-component-id",
-     *     ...
-     *   }
-     * }
-     */
-    get editorUIComponentId() {
-        const metadata = this._getMetadata();
-        if (metadata && 'editor' in metadata && 'ui-component-id' in metadata['editor'])
{
-            return metadata['editor']['ui-component-id'];
-        } else {
-            return null;
-        }
+  /**
+   * Get the UI component id for the editor component to use for this input.
+   * Returns null if there is no editor UI component id.
+   *
+   * The expected JSON schema for the editor UI component id is the following:
+   * {
+   *   "editor": {
+   *     "ui-component-id": "input-editor-component-id",
+   *     ...
+   *   }
+   * }
+   */
+  get editorUIComponentId() {
+    const metadata = this._getMetadata();
+    if (metadata && 'editor' in metadata && 'ui-component-id' in metadata['editor'])
{
+      return metadata['editor']['ui-component-id'];
+    } else {
+      return null;
     }
+  }
 
-    /**
-     * Get the configuration for the editor component, which will be available
-     * to the editor component for customizing its look and functionality.
-     * Returns empty object if there is no editor config.
-     *
-     * The expected JSON schema for the editor config is the following:
-     * {
-     *   "editor": {
-     *     "config": {
-     *       ... anything can go here ...
-     *     }
-     *     ...
-     *   }
-     * }
-     */
-    get editorConfig() {
-        const metadata = this._getMetadata();
-        if (metadata && 'editor' in metadata && 'config' in metadata['editor'])
{
-            return metadata['editor']['config'];
-        } else {
-            return {};
-        }
+  /**
+   * Get the configuration for the editor component, which will be available
+   * to the editor component for customizing its look and functionality.
+   * Returns empty object if there is no editor config.
+   *
+   * The expected JSON schema for the editor config is the following:
+   * {
+   *   "editor": {
+   *     "config": {
+   *       ... anything can go here ...
+   *     }
+   *     ...
+   *   }
+   * }
+   */
+  get editorConfig() {
+    const metadata = this._getMetadata();
+    if (metadata && 'editor' in metadata && 'config' in metadata['editor'])
{
+      return metadata['editor']['config'];
+    } else {
+      return {};
     }
+  }
 
-    /**
-     * Get the validations for the editor component. See ValidatorFactory for a
-     * list of available validations. Returns empty array if there are no
-     * validations.
-     *
-     * The expected JSON schema for the editor validations is the following:
-     * {
-     *   "editor": {
-     *     "validations": [
-     *       {
-     *         "type": "validation-name",
-     *         "value": "some value for configuring validation, passed to validator constructor",
-     *         "message": "(Optional) custom validation error message"
-     *       },
-     *       ... additional validations go here ...
-     *     ]
-     *     ...
-     *   }
-     * }
-     *
-     * Note: "message" is optional for all validations.
-     */
-    get editorValidations() {
-        const metadata = this._getMetadata();
-        if (metadata && 'editor' in metadata && 'validations' in metadata['editor'])
{
-            return metadata['editor']['validations'];
-        } else {
-            return [];
-        }
+  /**
+   * Get the validations for the editor component. See ValidatorFactory for a
+   * list of available validations. Returns empty array if there are no
+   * validations.
+   *
+   * The expected JSON schema for the editor validations is the following:
+   * {
+   *   "editor": {
+   *     "validations": [
+   *       {
+   *         "type": "validation-name",
+   *         "value": "some value for configuring validation, passed to validator constructor",
+   *         "message": "(Optional) custom validation error message"
+   *       },
+   *       ... additional validations go here ...
+   *     ]
+   *     ...
+   *   }
+   * }
+   *
+   * Note: "message" is optional for all validations.
+   */
+  get editorValidations() {
+    const metadata = this._getMetadata();
+    if (metadata && 'editor' in metadata && 'validations' in metadata['editor'])
{
+      return metadata['editor']['validations'];
+    } else {
+      return [];
     }
+  }
 
-    _getMetadata() {
-        // metaData could really be anything, here we expect it to be an object
-        // so safely check if it is first
-        if (this.metaData && typeof this.metaData === 'object') {
-            return this.metaData;
-        } else {
-            return null;
-        }
+  _getMetadata() {
+    // metaData could really be anything, here we expect it to be an object
+    // so safely check if it is first
+    if (this.metaData && typeof this.metaData === 'object') {
+      return this.metaData;
+    } else {
+      return null;
     }
+  }
 
-    validate(experiment, value = undefined) {
-        let inputValue = typeof value != 'undefined' ? value : this.value;
-        let results = {};
-        let valueErrorMessages = [];
-        if (this.isRequired && this.isEmpty(inputValue)) {
-            valueErrorMessages.push('This field is required.');
-        }
-        // Run through any validations if configured
-        if (this.editorValidations.length > 0) {
-            const validatorFactory = new ValidatorFactory();
-            valueErrorMessages = valueErrorMessages.concat(validatorFactory.validate(this.editorValidations,
inputValue));
-        }
-        if (valueErrorMessages.length > 0) {
-            results['value'] = valueErrorMessages;
-        }
-        return results;
+  validate(experiment, value = undefined) {
+    let inputValue = typeof value != 'undefined' ? value : this.value;
+    let results = {};
+    let valueErrorMessages = [];
+    if (this.isRequired && this.isEmpty(inputValue)) {
+      valueErrorMessages.push('This field is required.');
+    }
+    // Run through any validations if configured
+    if (this.editorValidations.length > 0) {
+      const validatorFactory = new ValidatorFactory();
+      valueErrorMessages = valueErrorMessages.concat(validatorFactory.validate(this.editorValidations,
inputValue));
+    }
+    if (valueErrorMessages.length > 0) {
+      results['value'] = valueErrorMessages;
     }
+    return results;
+  }
 }


Mime
View raw message