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 d969781eb6c61f5343eccb03bfdf42a0cfbc50e2 Author: Marcus Christie <[email protected]> AuthorDate: Thu Sep 6 10:21:29 2018 -0400 AIRAVATA-2876 Application output field editor --- django_airavata/apps/admin/package-lock.json | 14 +++- .../applications/ApplicationInputFieldEditor.vue | 3 - .../applications/ApplicationInterfaceEditor.vue | 44 ++++++++++-- .../applications/ApplicationOutputFieldEditor.vue | 81 ++++++++++++++++++++++ django_airavata/apps/api/package-lock.json | 5 ++ django_airavata/apps/api/package.json | 3 +- .../js/models/OutputDataObjectType.js | 56 +++++++++++---- 7 files changed, 180 insertions(+), 26 deletions(-) diff --git a/django_airavata/apps/admin/package-lock.json b/django_airavata/apps/admin/package-lock.json index 725c86a..6d32a10 100644 --- a/django_airavata/apps/admin/package-lock.json +++ b/django_airavata/apps/admin/package-lock.json @@ -2873,7 +2873,8 @@ "version": "file:../api", "requires": { "babel-runtime": "^6.26.0", - "url-parse": "^1.4.3" + "url-parse": "^1.4.3", + "uuid": "^3.3.2" }, "dependencies": { "ansi-regex": { @@ -4124,6 +4125,10 @@ "bundled": true, "optional": true }, + "uuid": { + "version": "3.3.2", + "bundled": true + }, "v8flags": { "version": "2.1.1", "bundled": true, @@ -5916,7 +5921,8 @@ "bundled": true, "requires": { "babel-runtime": "^6.26.0", - "url-parse": "^1.4.3" + "url-parse": "^1.4.3", + "uuid": "^3.3.2" }, "dependencies": { "ansi-regex": { @@ -7167,6 +7173,10 @@ "bundled": true, "optional": true }, + "uuid": { + "version": "3.3.2", + "bundled": true + }, "v8flags": { "version": "2.1.1", "bundled": true, 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 0730ae4..a03afa1 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 @@ -91,9 +91,6 @@ export default { } }, methods: { - copyValue() { - return this.value.clone(); - }, doFocus() { this.$refs.nameInput.focus(); this.$el.scrollIntoView(); 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 891b105..5074313 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,14 +26,14 @@ <h1 class="h5 mb-4"> Input Fields </h1> - <draggable v-model="data.applicationInputs" :options="dragOptions" @start="onDragStart" @end="onDragEnd" @input="emitChanged"> + <draggable v-model="data.applicationInputs" :options="dragOptions" @start="onDragStart" @end="onDragEnd"> <application-input-field-editor v-for="(input, index) in data.applicationInputs" :value="input" :key="index" :id="'app-input-'+index" :focus="index === focusApplicationInputIndex" :collapse="collapseApplicationInputs" @input="updatedInput($event, index)" @delete="deleteInput($event, index)" /> </draggable> </div> </div> - <div class="row"> + <div class="row mb-4"> <div class="col"> <b-button variant="secondary" @click="addApplicationInput"> Add application input @@ -42,6 +42,22 @@ </div> <div class="row"> <div class="col"> + <h1 class="h5 mb-4"> + Output Fields + </h1> + <application-output-field-editor v-for="output in data.applicationOutputs" :value="output" :key="output.key" :focus="output.key === focusApplicationOutputKey" + @input="updatedOutput" @delete="deleteOutput(output)" /> + </div> + </div> + <div class="row mb-4"> + <div class="col"> + <b-button variant="secondary" @click="addApplicationOutput"> + Add application output + </b-button> + </div> + </div> + <div class="row mb-4"> + <div class="col"> <b-button variant="primary" @click="save"> Save </b-button> @@ -57,6 +73,7 @@ import { models } from "django-airavata-api"; import vmodel_mixin from "../commons/vmodel_mixin"; import ApplicationInputFieldEditor from "./ApplicationInputFieldEditor.vue"; +import ApplicationOutputFieldEditor from "./ApplicationOutputFieldEditor.vue"; import draggable from "vuedraggable"; @@ -70,6 +87,7 @@ export default { }, components: { ApplicationInputFieldEditor, + ApplicationOutputFieldEditor, draggable }, computed: { @@ -80,6 +98,7 @@ export default { data() { return { focusApplicationInputIndex: null, + focusApplicationOutputKey: null, dragOptions: { handle: ".drag-handle" }, @@ -95,7 +114,6 @@ export default { }, updatedInput(newValue, index) { Object.assign(this.data.applicationInputs[index], newValue); - this.emitChanged(); }, addApplicationInput() { this.data.applicationInputs.push(new models.InputDataObjectType()); @@ -104,14 +122,28 @@ export default { deleteInput(e, index) { this.data.applicationInputs.splice(index, 1); }, + updatedOutput(newValue) { + const output = this.data.applicationOutputs.find( + o => o.key === newValue.key + ); + Object.assign(output, newValue); + }, + addApplicationOutput() { + const newOutput = new models.OutputDataObjectType(); + this.data.applicationOutputs.push(newOutput); + this.focusApplicationOutputKey = newOutput.key; + }, + deleteOutput(output) { + const outputIndex = this.data.applicationOutputs.findIndex( + o => o.key === output.key + ); + this.data.applicationOutputs.splice(outputIndex, 1); + }, onDragStart() { this.collapseApplicationInputs = true; }, onDragEnd() { this.collapseApplicationInputs = false; - }, - emitChanged() { - this.$emit("input", this.data); } } }; diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationOutputFieldEditor.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationOutputFieldEditor.vue new file mode 100644 index 0000000..7db4421 --- /dev/null +++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationOutputFieldEditor.vue @@ -0,0 +1,81 @@ +<template> + <b-card> + <div class="d-flex align-items-center" slot="header"> + <div class="mr-auto">Output Field: {{ data.name }}</div> + <b-link class="text-secondary" @click="deleteApplicationOutput"> + <i class="fa fa-trash"></i> + <span class="sr-only">Delete</span> + </b-link> + </div> + <b-form-group label="Name" :label-for="id+'-name'"> + <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="Value" :label-for="id+'-value'"> + <b-form-input :id="id+'-value'" type="text" v-model="data.value"></b-form-input> + </b-form-group> + <b-form-group label="Type" :label-for="id+'-type'"> + <b-form-select :id="id+'-type'" v-model="data.type" :options="outputTypeOptions" /> + </b-form-group> + <b-form-group label="Application Argument" :label-for="id+'-argument'"> + <b-form-input :id="id+'-argument'" type="text" v-model="data.applicationArgument"></b-form-input> + </b-form-group> + <div class="d-flex"> + <b-form-group class="flex-fill" label="Is Required" :label-for="id+'-required'"> + <b-form-radio-group :id="id+'-required'" v-model="data.isRequired" :options="trueFalseOptions"> + </b-form-radio-group> + </b-form-group> + <b-form-group class="flex-fill" label="Required on Command Line" :label-for="id+'-required-command-line'"> + <b-form-radio-group :id="id+'-required-command-line'" v-model="data.requiredToAddedToCommandLine" :options="trueFalseOptions"> + </b-form-radio-group> + </b-form-group> + </div> + </b-card> +</template> + +<script> +import { models } from "django-airavata-api"; +import vmodel_mixin from "../commons/vmodel_mixin"; +export default { + name: "application-output-field-editor", + mixins: [vmodel_mixin], + props: { + value: { + type: models.OutputDataObjectType + }, + focus: { + type: Boolean + } + }, + computed: { + outputTypeOptions() { + return models.DataType.values.map(dataType => { + return { + value: dataType, + text: dataType.name + }; + }); + }, + trueFalseOptions() { + return [{ text: "True", value: true }, { text: "False", value: false }]; + }, + id() { + return "id-" + this.data.key; + } + }, + methods: { + doFocus() { + this.$refs.nameInput.focus(); + this.$el.scrollIntoView(); + }, + deleteApplicationOutput() { + this.$emit("delete"); + } + }, + mounted() { + if (this.focus) { + this.doFocus(); + } + } +}; +</script> + diff --git a/django_airavata/apps/api/package-lock.json b/django_airavata/apps/api/package-lock.json index c7097a8..8dd5300 100644 --- a/django_airavata/apps/api/package-lock.json +++ b/django_airavata/apps/api/package-lock.json @@ -2143,6 +2143,11 @@ "dev": true, "optional": true }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, "v8flags": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", diff --git a/django_airavata/apps/api/package.json b/django_airavata/apps/api/package.json index 7073e3d..a595c69 100644 --- a/django_airavata/apps/api/package.json +++ b/django_airavata/apps/api/package.json @@ -13,7 +13,8 @@ }, "dependencies": { "babel-runtime": "^6.26.0", - "url-parse": "^1.4.3" + "url-parse": "^1.4.3", + "uuid": "^3.3.2" }, "devDependencies": { "babel-cli": "^6.26.0", diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/OutputDataObjectType.js b/django_airavata/apps/api/static/django_airavata_api/js/models/OutputDataObjectType.js index f4d6d6b..50ab118 100644 --- a/django_airavata/apps/api/static/django_airavata_api/js/models/OutputDataObjectType.js +++ b/django_airavata/apps/api/static/django_airavata_api/js/models/OutputDataObjectType.js @@ -1,22 +1,50 @@ import BaseModel from './BaseModel'; +import DataType from './DataType'; +import uuidv4 from 'uuid/v4'; const FIELDS = [ - 'name', - 'value', - 'type', - 'applicationArgument', - 'isRequired', - 'requiredToAddedToCommandLine', - 'dataMovement', - 'location', - 'searchQuery', - 'outputStreaming', - 'storageResourceId', + 'name', + 'value', + { + name: 'type', + type: DataType, + default: DataType.URI, + }, + 'applicationArgument', + { + name: 'isRequired', + type: 'boolean', + default: false + }, + { + name: 'requiredToAddedToCommandLine', + type: 'boolean', + default: false, + }, + { + name: 'dataMovement', + type: 'boolean', + default: false + }, + 'location', + 'searchQuery', + { + name: 'outputStreaming', + type: 'boolean', + default: false + }, + 'storageResourceId', ]; export default class OutputDataObjectType extends BaseModel { - constructor(data = {}) { - super(FIELDS, data); - } + constructor(data = {}) { + super(FIELDS, data); + // Copy key when cloning a model + this._key = data.key ? data.key : uuidv4(); + } + + get key() { + return this._key; + } }
