You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2018/04/23 17:23:21 UTC

[airavata-django-portal] branch master updated (5cbcdae -> af9df3c)

This is an automated email from the ASF dual-hosted git repository.

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


    from 5cbcdae  Fixing layout of array-view-main
     new b644c94  AIRAVATA-2611 Factor out exp input editors into separate components
     new 874ebb4  AIRAVATA-2611 Exp input editors validate value and dispatch events
     new af9df3c  AIRAVATA-2611 InputEditorMixin for common input editor functionality

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../django_airavata_api/js/models/Experiment.js    | 13 ----
 .../js/models/InputDataObjectType.js               |  5 +-
 .../js/components/experiment/ExperimentEditor.vue  | 74 +++++++++++-----------
 .../experiment/input-editors/FileInputEditor.vue   | 73 +++++++++++++++++++++
 .../experiment/input-editors/InputEditorMixin.js   | 63 ++++++++++++++++++
 .../experiment/input-editors/StringInputEditor.vue | 74 ++++++++++++++++++++++
 6 files changed, 249 insertions(+), 53 deletions(-)
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorMixin.js
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.

[airavata-django-portal] 01/03: AIRAVATA-2611 Factor out exp input editors into separate components

Posted by ma...@apache.org.
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 b644c9458a70cedd7c1f8fac01758c5561810d59
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Mon Apr 23 10:42:10 2018 -0400

    AIRAVATA-2611 Factor out exp input editors into separate components
---
 .../js/components/experiment/ExperimentEditor.vue  | 42 ++++++++++------------
 .../experiment/input-editors/FileInputEditor.vue   | 37 +++++++++++++++++++
 .../experiment/input-editors/StringInputEditor.vue | 38 ++++++++++++++++++++
 3 files changed, 94 insertions(+), 23 deletions(-)

diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentEditor.vue
index 517f2db..29be831 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentEditor.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentEditor.vue
@@ -50,17 +50,12 @@
                             <h2 class="h6 mb-3">
                                 Application Inputs
                             </h2>
-                            <b-form-group v-for="experimentInput in localExperiment.experimentInputs"
-                                    :label="experimentInput.name" :label-for="experimentInput.name" :key="experimentInput.name"
-                                    :feedback="getValidationFeedback(['experimentInputs', experimentInput.name, 'value'])"
-                                    :state="getValidationState(['experimentInputs', experimentInput.name, 'value'])">
-                                <b-form-input v-if="isSimpleInput(experimentInput)" :id="experimentInput.name" type="text" v-model="experimentInput.value" required
-                                    :placeholder="experimentInput.userFriendlyDescription"
-                                    :state="getValidationState(['experimentInputs', experimentInput.name, 'value'])"></b-form-input>
-                                <b-form-file v-if="isFileInput(experimentInput)" :id="experimentInput.name" type="text" v-model="experimentInput.value" required
-                                    :placeholder="experimentInput.userFriendlyDescription"
-                                    :state="getValidationState(['experimentInputs', experimentInput.name, 'value'])"></b-form-file>
-                            </b-form-group>
+                            <component :is="getInputEditorComponentName(experimentInput)"
+                                v-for="experimentInput in localExperiment.experimentInputs"
+                                :experiment="localExperiment"
+                                :experiment-input="experimentInput"
+                                v-model="experimentInput.value"
+                                :key="experimentInput.name"/>
                         </div>
                     </div>
                 </div>
@@ -102,6 +97,8 @@
 <script>
 import ComputationalResourceSchedulingEditor from './ComputationalResourceSchedulingEditor.vue'
 import GroupResourceProfileSelector from './GroupResourceProfileSelector.vue'
+import StringInputEditor from './input-editors/StringInputEditor.vue'
+import FileInputEditor from './input-editors/FileInputEditor.vue'
 import {models, services, utils as apiUtils} from 'django-airavata-api'
 import {utils} from 'django-airavata-common-ui'
 
@@ -130,6 +127,8 @@ export default {
     components: {
         ComputationalResourceSchedulingEditor,
         GroupResourceProfileSelector,
+        StringInputEditor,
+        FileInputEditor,
     },
     mounted: function () {
         services.ProjectService.listAll()
@@ -214,18 +213,15 @@ export default {
         getValidationState: function(properties) {
             return this.getValidationFeedback(properties) ? 'invalid' : null;
         },
-        isSimpleInput: function(experimentInput) {
-            return [
-                models.DataType.STRING,
-                models.DataType.FLOAT,
-                models.DataType.INTEGER,
-            ].indexOf(experimentInput.type) >= 0;
-        },
-        isFileInput: function(experimentInput) {
-            return [
-                models.DataType.URI,
-            ].indexOf(experimentInput.type) >= 0;
-        },
+        getInputEditorComponentName: function(experimentInput) {
+            if (experimentInput.type === models.DataType.STRING) {
+                return 'string-input-editor';
+            } else if (experimentInput.type === models.DataType.URI) {
+                return 'file-input-editor';
+            }
+            // Default
+            return 'string-input-editor';
+        }
     },
     watch: {
         experiment: function(newValue) {
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue
new file mode 100644
index 0000000..2d5dbeb
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue
@@ -0,0 +1,37 @@
+<template>
+    <b-form-group :label="experimentInput.name" :label-for="experimentInput.name">
+        <b-form-file :id="experimentInput.name" v-model="data" required
+            :placeholder="experimentInput.userFriendlyDescription"
+            @input="emitValueChanged"/>
+    </b-form-group>
+</template>
+
+<script>
+import {models} from 'django-airavata-api'
+export default {
+    name: 'file-input-editor',
+    props: {
+        value: {
+            required: false,
+        },
+        experiment: {
+            type: models.Experiment,
+            required: true,
+        },
+        experimentInput: {
+            type: models.InputDataObjectType,
+            required: true,
+        },
+    },
+    data () {
+        return {
+            data: this.value,
+        }
+    },
+    methods: {
+        emitValueChanged: function() {
+            this.$emit('input', this.data);
+        },
+    },
+}
+</script>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue
new file mode 100644
index 0000000..27628b0
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue
@@ -0,0 +1,38 @@
+<template>
+    <b-form-group :label="experimentInput.name" :label-for="experimentInput.name">
+        <b-form-input :id="experimentInput.name" type="text" v-model="data" required
+            :placeholder="experimentInput.userFriendlyDescription"
+            @input="emitValueChanged"/>
+    </b-form-group>
+</template>
+
+<script>
+import {models} from 'django-airavata-api'
+export default {
+    name: 'string-input-editor',
+    props: {
+        value: {
+            type: String,
+            required: false,
+        },
+        experiment: {
+            type: models.Experiment,
+            required: true,
+        },
+        experimentInput: {
+            type: models.InputDataObjectType,
+            required: true,
+        },
+    },
+    data () {
+        return {
+            data: this.value,
+        }
+    },
+    methods: {
+        emitValueChanged: function() {
+            this.$emit('input', this.data);
+        },
+    },
+}
+</script>
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.

[airavata-django-portal] 03/03: AIRAVATA-2611 InputEditorMixin for common input editor functionality

Posted by ma...@apache.org.
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 af9df3c136d8f10f030f6d9f938d943aedd64895
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Mon Apr 23 13:22:45 2018 -0400

    AIRAVATA-2611 InputEditorMixin for common input editor functionality
---
 .../experiment/input-editors/InputEditorMixin.js   | 63 ++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorMixin.js b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorMixin.js
new file mode 100644
index 0000000..cd56b99
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorMixin.js
@@ -0,0 +1,63 @@
+// InputEditorMixin: mixin for experiment InputEditors, provides basic v-model
+// and validation functionality and defines the basic props interface
+// (experimentInput and experiment).
+import {models} from 'django-airavata-api'
+export default {
+    props: {
+        value: {
+            required: true,
+        },
+        experiment: {
+            type: models.Experiment,
+            required: true,
+        },
+        experimentInput: {
+            type: models.InputDataObjectType,
+            required: true,
+        },
+    },
+    data () {
+        return {
+            data: this.value,
+            inputHasBegun: false,
+        }
+    },
+    computed: {
+        validationResults: function() {
+            return this.experimentInput.validate(this.experiment, this.data);
+        },
+        valid: function() {
+            return Object.keys(this.validationResults).length === 0;
+        },
+        validationFeedback: function() {
+            // Only display validation feedback after the user has provided
+            // input so that missing required value errors are only displayed
+            // after interacting with the input editor
+            return this.inputHasBegun && 'value' in this.validationResults
+                ? this.validationResults['value']
+                : null;
+        },
+        validationState: function() {
+            return this.inputHasBegun && 'value' in this.validationResults
+                ? 'invalid'
+                : null;
+        },
+    },
+    methods: {
+        valueChanged: function() {
+            this.inputHasBegun = true;
+            this.$emit('input', this.data);
+            this.checkValidation();
+        },
+        checkValidation: function() {
+            if (this.valid) {
+                this.$emit('valid');
+            } else {
+                this.$emit('invalid');
+            }
+        }
+    },
+    mounted: function() {
+        this.checkValidation();
+    }
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.

[airavata-django-portal] 02/03: AIRAVATA-2611 Exp input editors validate value and dispatch events

Posted by ma...@apache.org.
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 874ebb4f2c04370ba6b053291482fe00fa67db9b
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Mon Apr 23 13:02:47 2018 -0400

    AIRAVATA-2611 Exp input editors validate value and dispatch events
---
 .../django_airavata_api/js/models/Experiment.js    | 13 -------
 .../js/models/InputDataObjectType.js               |  5 ++-
 .../js/components/experiment/ExperimentEditor.vue  | 40 ++++++++++----------
 .../experiment/input-editors/FileInputEditor.vue   | 44 ++++++++++++++++++++--
 .../experiment/input-editors/StringInputEditor.vue | 44 ++++++++++++++++++++--
 5 files changed, 104 insertions(+), 42 deletions(-)

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 90e6637..d45637e 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
@@ -74,19 +74,6 @@ export default class Experiment extends BaseModel {
 
     validate() {
         let validationResults = {};
-        const experimentInputsValidation = this.experimentInputs
-            .map(experimentInput => {
-                const validation = experimentInput.validate();
-                if (validation && 'value' in validation) {
-                    return {[experimentInput.name]: validation};
-                } else {
-                    return null;
-                }
-            })
-            .reduce((accumulator, currentValue) => Object.assign(accumulator, currentValue), {});
-        if (Object.keys(experimentInputsValidation).length > 0) {
-            validationResults['experimentInputs'] = experimentInputsValidation;
-        }
         const userConfigurationDataValidation = this.userConfigurationData.validate();
         if (Object.keys(userConfigurationDataValidation).length > 0) {
             validationResults['userConfigurationData'] = userConfigurationDataValidation;
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 dfe2846..eb5407b 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
@@ -26,9 +26,10 @@ export default class InputDataObjectType extends BaseModel {
         super(FIELDS, data);
     }
 
-    validate() {
+    validate(experiment, value = undefined) {
+        let inputValue = typeof value != 'undefined' ? value : this.value;
         let results = {};
-        if (this.isRequired && this.isEmpty(this.value)) {
+        if (this.isRequired && this.isEmpty(inputValue)) {
             results['value'] = 'This field is required.';
         }
         return results;
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentEditor.vue
index 29be831..94a8d44 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentEditor.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentEditor.vue
@@ -55,7 +55,9 @@
                                 :experiment="localExperiment"
                                 :experiment-input="experimentInput"
                                 v-model="experimentInput.value"
-                                :key="experimentInput.name"/>
+                                :key="experimentInput.name"
+                                @invalid="recordInvalidInputEditorValue(experimentInput.name)"
+                                @valid="recordValidInputEditorValue(experimentInput.name)"/>
                         </div>
                     </div>
                 </div>
@@ -122,6 +124,7 @@ export default {
         return {
             projects: [],
             localExperiment: this.experiment.clone(),
+            invalidInputs: [],
         }
     },
     components: {
@@ -141,9 +144,12 @@ export default {
                 text: project.name,
             }));
         },
-        isSaveDisabled: function() {
+        valid: function() {
             const validation = this.localExperiment.validate();
-            return Object.keys(validation).length > 0;
+            return Object.keys(validation).length === 0 && this.invalidInputs.length === 0;
+        },
+        isSaveDisabled: function() {
+            return !this.valid;
         },
     },
     methods: {
@@ -192,21 +198,6 @@ export default {
             });
             return Promise.all(uploads);
         },
-        getApplicationInputState: function(applicationInput) {
-            const validation = this.getApplicationInputValidation(applicationInput);
-            return validation !== null ? 'invalid' : null;
-        },
-        getApplicationInputFeedback: function(applicationInput) {
-            const validation = this.getApplicationInputValidation(applicationInput);
-            return validation !== null ? validation['value'] : null;
-        },
-        getApplicationInputValidation: function(applicationInput) {
-            const validationResults = applicationInput.validate();
-            if (validationResults !== null && 'value' in validationResults) {
-                return validationResults;
-            }
-            return null;
-        },
         getValidationFeedback: function(properties) {
             return utils.getProperty(this.localExperiment.validate(), properties);
         },
@@ -221,7 +212,18 @@ export default {
             }
             // Default
             return 'string-input-editor';
-        }
+        },
+        recordInvalidInputEditorValue: function(experimentInputName) {
+            if (!this.invalidInputs.includes(experimentInputName)) {
+                this.invalidInputs.push(experimentInputName);
+            }
+        },
+        recordValidInputEditorValue: function(experimentInputName) {
+            if (this.invalidInputs.includes(experimentInputName)) {
+                const index = this.invalidInputs.indexOf(experimentInputName);
+                this.invalidInputs.splice(index, 1);
+            }
+        },
     },
     watch: {
         experiment: function(newValue) {
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue
index 2d5dbeb..4efa9b1 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue
@@ -1,8 +1,10 @@
 <template>
-    <b-form-group :label="experimentInput.name" :label-for="experimentInput.name">
-        <b-form-file :id="experimentInput.name" v-model="data" required
+    <b-form-group :label="experimentInput.name" :label-for="experimentInput.name"
+        :feedback="validationFeedback" :state="validationState">
+        <b-form-file :id="experimentInput.name" v-model="data"
             :placeholder="experimentInput.userFriendlyDescription"
-            @input="emitValueChanged"/>
+            :state="validationState"
+            @input="valueChanged"/>
     </b-form-group>
 </template>
 
@@ -26,12 +28,46 @@ export default {
     data () {
         return {
             data: this.value,
+            inputHasBegun: false,
         }
     },
+    computed: {
+        validationResults: function() {
+            return this.experimentInput.validate(this.experiment, this.data);
+        },
+        valid: function() {
+            return Object.keys(this.validationResults).length === 0;
+        },
+        validationFeedback: function() {
+            // Only display validation feedback after the user has provided
+            // input so that missing required value errors are only displayed
+            // after interacting with the input editor
+            return this.inputHasBegun && 'value' in this.validationResults
+                ? this.validationResults['value']
+                : null;
+        },
+        validationState: function() {
+            return this.inputHasBegun && 'value' in this.validationResults
+                ? 'invalid'
+                : null;
+        },
+    },
     methods: {
-        emitValueChanged: function() {
+        valueChanged: function() {
+            this.inputHasBegun = true;
             this.$emit('input', this.data);
+            this.checkValidation();
         },
+        checkValidation: function() {
+            if (this.valid) {
+                this.$emit('valid');
+            } else {
+                this.$emit('invalid');
+            }
+        }
     },
+    mounted: function() {
+        this.checkValidation();
+    }
 }
 </script>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue
index 27628b0..4a3a96a 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue
@@ -1,8 +1,10 @@
 <template>
-    <b-form-group :label="experimentInput.name" :label-for="experimentInput.name">
-        <b-form-input :id="experimentInput.name" type="text" v-model="data" required
+    <b-form-group :label="experimentInput.name" :label-for="experimentInput.name"
+        :feedback="validationFeedback" :state="validationState">
+        <b-form-input :id="experimentInput.name" type="text" v-model="data"
             :placeholder="experimentInput.userFriendlyDescription"
-            @input="emitValueChanged"/>
+            :state="validationState"
+            @input="valueChanged"/>
     </b-form-group>
 </template>
 
@@ -27,12 +29,46 @@ export default {
     data () {
         return {
             data: this.value,
+            inputHasBegun: false,
         }
     },
+    computed: {
+        validationResults: function() {
+            return this.experimentInput.validate(this.experiment, this.data);
+        },
+        valid: function() {
+            return Object.keys(this.validationResults).length === 0;
+        },
+        validationFeedback: function() {
+            // Only display validation feedback after the user has provided
+            // input so that missing required value errors are only displayed
+            // after interacting with the input editor
+            return this.inputHasBegun && 'value' in this.validationResults
+                ? this.validationResults['value']
+                : null;
+        },
+        validationState: function() {
+            return this.inputHasBegun && 'value' in this.validationResults
+                ? 'invalid'
+                : null;
+        },
+    },
     methods: {
-        emitValueChanged: function() {
+        valueChanged: function() {
+            this.inputHasBegun = true;
             this.$emit('input', this.data);
+            this.checkValidation();
         },
+        checkValidation: function() {
+            if (this.valid) {
+                this.$emit('valid');
+            } else {
+                this.$emit('invalid');
+            }
+        }
     },
+    mounted: function() {
+        this.checkValidation();
+    }
 }
 </script>
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.