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/01/11 16:18:47 UTC
[airavata-django-portal] branch master updated (08ef4ae -> d0b50f3)
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 08ef4ae AIRAVATA-2598 Implement saving experiment
new a103b6e AIRAVATA-2598 Launch an experiment
new 8615c84 AIRAVATA-2598 Display validation of required inputs
new 26dc27f AIRAVATA-2598 Disable save when app inputs are invalid
new d0b50f3 AIRAVATA-2598 Allow optional CharFields to be null or blank
The 4 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/BaseModel.js | 4 ++
.../models/ComputationalResourceSchedulingModel.js | 30 ++--------
.../django_airavata_api/js/models/Experiment.js | 24 ++++++--
.../js/models/InputDataObjectType.js | 26 +++------
.../django_airavata_api/js/models/Project.js | 2 +-
.../js/models/UserConfigurationData.js | 18 +-----
.../js/services/ApplicationInterfaceService.js | 2 +-
.../js/services/ExperimentService.js | 30 +++++++++-
.../django_airavata_api/js/utils/FetchUtils.js | 23 +++++++-
django_airavata/apps/api/thrift_utils.py | 6 +-
django_airavata/apps/api/views.py | 8 ++-
.../js/components/experiment/ExperimentEditor.vue | 68 +++++++++++++++-------
django_airavata/settings_local.py.sample | 1 +
13 files changed, 147 insertions(+), 95 deletions(-)
--
To stop receiving notification emails like this one, please contact
['"commits@airavata.apache.org" <co...@airavata.apache.org>'].
[airavata-django-portal] 01/04: AIRAVATA-2598 Launch an experiment
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 a103b6e03b2a3751c14a99255d1079f85883ef4f
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Wed Jan 10 12:05:54 2018 -0500
AIRAVATA-2598 Launch an experiment
---
.../js/services/ApplicationInterfaceService.js | 2 +-
.../js/services/ExperimentService.js | 30 ++++++++++++++++--
.../django_airavata_api/js/utils/FetchUtils.js | 23 +++++++++++++-
django_airavata/apps/api/thrift_utils.py | 12 +++++++
django_airavata/apps/api/views.py | 8 +++--
.../js/components/experiment/ExperimentEditor.vue | 37 ++++++++++++----------
django_airavata/settings_local.py.sample | 1 +
7 files changed, 89 insertions(+), 24 deletions(-)
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/services/ApplicationInterfaceService.js b/django_airavata/apps/api/static/django_airavata_api/js/services/ApplicationInterfaceService.js
index f0eeb0c..796c666 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/services/ApplicationInterfaceService.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/services/ApplicationInterfaceService.js
@@ -25,7 +25,7 @@ class ApplicationIterfaceService {
}
getComputeResources(appInterfaceId) {
- return FetchUtils.get('/api/application-interfaces/' + encodeURIComponent(appInterfaceId) + '/compute_resources');
+ return FetchUtils.get('/api/application-interfaces/' + encodeURIComponent(appInterfaceId) + '/compute_resources/');
}
}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/services/ExperimentService.js b/django_airavata/apps/api/static/django_airavata_api/js/services/ExperimentService.js
index b840b86..0aa81b5 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/services/ExperimentService.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/services/ExperimentService.js
@@ -17,12 +17,36 @@ class ExperimentService {
.then(result => new Experiment(result));
}
- update() {
- // TODO
+ update(experiment) {
+ return FetchUtils.put('/api/experiments/'
+ + encodeURIComponent(experiment.experimentId) + '/',
+ JSON.stringify(experiment))
+ .then(result => new Experiment(result));
+ }
+
+ save(experiment) {
+ if (experiment.experimentId) {
+ return this.update(experiment);
+ } else {
+ return this.create(experiment);
+ }
}
get() {
- // TODO
+ return FetchUtils.get('/api/experiments/'
+ + encodeURIComponent(experiment.experimentId) + '/')
+ .then(result => new Experiment(result));
+ }
+
+ launch(experimentId) {
+ return FetchUtils.post('/api/experiments/' + encodeURIComponent(experimentId) + '/launch/')
+ .then(result => {
+ if (result.success) {
+ return Promise.resolve(result);
+ } else {
+ return Promise.reject(result);
+ }
+ });
}
}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/utils/FetchUtils.js b/django_airavata/apps/api/static/django_airavata_api/js/utils/FetchUtils.js
index 8e09498..074e4ea 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/utils/FetchUtils.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/utils/FetchUtils.js
@@ -38,11 +38,32 @@ export default {
}
})
},
+ put: function (url, body, mediaType = "application/json") {
+ var headers = this.createHeaders(mediaType)
+ return fetch(url, {
+ method: 'put',
+ body: typeof body !== 'string' ? JSON.stringify(body) : body,
+ headers: headers,
+ credentials: "same-origin"
+ }).then((response) => {
+ if (response.ok) {
+ return Promise.resolve(response.json())
+ } else {
+ let error = new Error(response.statusText);
+ return response.json().then(json => {
+ error.data = json;
+ })
+ .then(() => Promise.reject(error),() => Promise.reject(error));
+ }
+ })
+ },
get: function (url, queryParams = "", mediaType = "application/json") {
if (queryParams && typeof(queryParams) != "string") {
queryParams = Object.keys(queryParams).map(key => encodeURIComponent(key) + "=" + encodeURIComponent(queryParams[key])).join("&")
}
- url=url+"?"+queryParams
+ if (queryParams) {
+ url=url+"?"+queryParams
+ }
var headers = this.createHeaders(mediaType)
return fetch(url, {
method: 'get',
diff --git a/django_airavata/apps/api/thrift_utils.py b/django_airavata/apps/api/thrift_utils.py
index 476cfbf..363a016 100644
--- a/django_airavata/apps/api/thrift_utils.py
+++ b/django_airavata/apps/api/thrift_utils.py
@@ -67,8 +67,20 @@ def create_serializer_class(thrift_data_type):
params[field_name] = serializer.create(params[field_name])
return params
+ def process_empty_char_fields(self, validated_data):
+ """Convert empty CharFields to None."""
+ fields = self.fields
+ params = copy.deepcopy(validated_data)
+ for field_name, serializer in fields.items():
+ if isinstance(serializer, CharField) \
+ and params.get(field_name, None) is not None \
+ and params[field_name].strip() == '':
+ params[field_name] = None
+ return params
+
def create(self, validated_data):
params = self.process_nested_fields(validated_data)
+ params = self.process_empty_char_fields(params)
return thrift_data_type(**params)
def update(self, instance, validated_data):
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index dcada13..7d2f6ed 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -239,6 +239,7 @@ class ExperimentViewSet(APIBackedViewSet):
def perform_create(self, serializer):
experiment = serializer.save()
+ experiment.userConfigurationData.storageId = settings.GATEWAY_DATA_STORE_RESOURCE_ID
experiment_id = self.request.airavata_client.createExperiment(self.authz_token, self.gateway_id, experiment)
experiment.experimentId = experiment_id
@@ -248,8 +249,11 @@ class ExperimentViewSet(APIBackedViewSet):
@detail_route(methods=['post'])
def launch(self, request, experiment_id=None):
- request.airavata_client.launchExperiment(request.authz_token, experiment_id, self.gateway_id)
- return Response({'success': True})
+ try:
+ request.airavata_client.launchExperiment(request.authz_token, experiment_id, self.gateway_id)
+ return Response({'success': True})
+ except Exception as e:
+ return Response({'success': False, 'errorMessage': e.message})
class ApplicationModuleViewSet(APIBackedViewSet):
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 8ec6543..76040ca 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
@@ -126,27 +126,30 @@ export default {
console.log(JSON.stringify(this.localExperiment));
// TODO: validate experiment
// save experiment
- if (this.localExperiment.experimentId) {
- services.ExperimentService.update(this.localExperiment)
- .then(experiment => {
- console.log(experiment);
- this.$emit('saved', experiment);
- });
- } else {
- services.ExperimentService.create(this.localExperiment)
- .then(experiment => {
- this.localExperiment.experimentId = experiment.experimentId;
- console.log(experiment);
- this.$emit('saved', experiment);
- });
- }
+ services.ExperimentService.save(this.localExperiment)
+ .then(experiment => {
+ this.localExperiment = experiment;
+ console.log(experiment);
+ alert('Experiment saved!');
+ this.$emit('saved', experiment);
+ });
},
saveAndLaunchExperiment: function() {
console.log(JSON.stringify(this.localExperiment));
// TODO: validate experiment
- // TODO: save experiment
- // TODO: set the experiment ID on the new experiment
- // TODO: dispatch save event with updated experiment
+ let savedExperiment = null;
+ services.ExperimentService.save(this.localExperiment)
+ .then(experiment => {
+ this.localExperiment = experiment;
+ return services.ExperimentService.launch(experiment.experimentId)
+ .then(result => {
+ alert('Experiment launched!');
+ this.$emit('savedAndLaunched', experiment);
+ });
+ })
+ .catch(result => {
+ console.log("Launch failed!", result);
+ });
},
},
watch: {
diff --git a/django_airavata/settings_local.py.sample b/django_airavata/settings_local.py.sample
index c847179..30037c3 100644
--- a/django_airavata/settings_local.py.sample
+++ b/django_airavata/settings_local.py.sample
@@ -32,6 +32,7 @@ GATEWAY_ID = 'default'
AIRAVATA_API_HOST = 'localhost'
AIRAVATA_API_PORT = 8930
AIRAVATA_API_SECURE = False
+GATEWAY_DATA_STORE_RESOURCE_ID = '...'
# Sharing API Configuration
SHARING_API_HOST = 'localhost'
--
To stop receiving notification emails like this one, please contact
"commits@airavata.apache.org" <co...@airavata.apache.org>.
[airavata-django-portal] 03/04: AIRAVATA-2598 Disable save when app
inputs are invalid
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 26dc27f1b81830d09fd8de935622d54f71f56c44
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Thu Jan 11 11:03:28 2018 -0500
AIRAVATA-2598 Disable save when app inputs are invalid
---
.../static/django_airavata_api/js/models/Experiment.js | 18 ++++++++++++++++++
.../js/components/experiment/ExperimentEditor.vue | 11 +++++++----
2 files changed, 25 insertions(+), 4 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 89404c8..d635a5f 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,4 +74,22 @@ export default class Experiment extends BaseModel {
constructor(data = {}) {
super(FIELDS, data);
}
+
+ validate() {
+ let validationResults = {};
+ let 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;
+ }
+ return validationResults;
+ }
}
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 77cbc00..e2f5581 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
@@ -69,10 +69,10 @@
</div>
<div class="row">
<div id="col-exp-buttons" class="col">
- <b-button variant="success" @click="saveAndLaunchExperiment">
+ <b-button variant="success" @click="saveAndLaunchExperiment" :disabled="isSaveDisabled">
Save and Launch
</b-button>
- <b-button variant="primary" @click="saveExperiment">
+ <b-button variant="primary" @click="saveExperiment" :disabled="isSaveDisabled">
Save
</b-button>
</div>
@@ -87,7 +87,6 @@ import {models, services} from 'django-airavata-api'
export default {
name: 'edit-experiment',
- // TODO: clone experiment instead of editing it directly
props: {
experiment: {
type: models.Experiment,
@@ -123,6 +122,10 @@ export default {
text: project.name,
}));
},
+ isSaveDisabled: function() {
+ const validation = this.localExperiment.validate();
+ return Object.keys(validation).length > 0;
+ },
},
methods: {
saveExperiment: function() {
@@ -160,7 +163,7 @@ export default {
},
getApplicationInputFeedback: function(applicationInput) {
const validation = this.getApplicationInputValidation(applicationInput);
- return validation !== null ? validation : null;
+ return validation !== null ? validation['value'] : null;
},
getApplicationInputValidation: function(applicationInput) {
const validationResults = applicationInput.validate();
--
To stop receiving notification emails like this one, please contact
"commits@airavata.apache.org" <co...@airavata.apache.org>.
[airavata-django-portal] 04/04: AIRAVATA-2598 Allow optional
CharFields to be null or blank
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 d0b50f31d5e1291c094fcc4ac9cf50bb5c86f2fb
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Thu Jan 11 11:17:49 2018 -0500
AIRAVATA-2598 Allow optional CharFields to be null or blank
---
.../models/ComputationalResourceSchedulingModel.js | 30 ++++------------------
.../django_airavata_api/js/models/Experiment.js | 6 +----
.../js/models/InputDataObjectType.js | 20 ++-------------
.../js/models/UserConfigurationData.js | 18 +++----------
django_airavata/apps/api/thrift_utils.py | 18 +++----------
5 files changed, 14 insertions(+), 78 deletions(-)
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ComputationalResourceSchedulingModel.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ComputationalResourceSchedulingModel.js
index 03c4782..f9cc61f 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/ComputationalResourceSchedulingModel.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ComputationalResourceSchedulingModel.js
@@ -8,31 +8,11 @@ const FIELDS = [
'queueName',
'wallTimeLimit',
'totalPhysicalMemory',
- {
- name: 'chessisNumber',
- type: 'string',
- default: '',
- },
- {
- name: 'staticWorkingDir',
- type: 'string',
- default: '',
- },
- {
- name: 'overrideLoginUserName',
- type: 'string',
- default: '',
- },
- {
- name: 'overrideScratchLocation',
- type: 'string',
- default: '',
- },
- {
- name: 'overrideAllocationProjectNumber',
- type: 'string',
- default: '',
- },
+ 'chessisNumber',
+ 'staticWorkingDir',
+ 'overrideLoginUserName',
+ 'overrideScratchLocation',
+ 'overrideAllocationProjectNumber',
];
export default class ComputationalResourceSchedulingModel extends BaseModel {
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 d635a5f..6066c3a 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
@@ -22,11 +22,7 @@ const FIELDS = [
name: 'creationTime',
type: 'date'
},
- {
- name: 'description',
- type: 'string',
- default: '',
- },
+ 'description',
'executionId',
{
name: 'enableEmailNotification',
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 496de53..5969555 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
@@ -8,34 +8,18 @@ const FIELDS = [
'applicationArgument',
'standardInput',
'userFriendlyDescription',
- {
- name: 'metaData',
- type: 'string',
- default: '',
- },
+ 'metaData',
'inputOrder',
'isRequired',
'requiredToAddedToCommandLine',
'dataStaged',
- {
- name: 'storageResourceId',
- type: 'string',
- default: '',
- },
+ 'storageResourceId',
'isReadOnly',
];
export default class InputDataObjectType extends BaseModel {
constructor(data = {}) {
super(FIELDS, data);
- // TODO: move into BaseModel
- // Convert null strings into empty strings
- if ('metaData' in this && this.metaData === null) {
- this.metaData = '';
- }
- if ('storageResourceId' in this && this.storageResourceId === null) {
- this.storageResourceId = '';
- }
}
validate() {
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/UserConfigurationData.js b/django_airavata/apps/api/static/django_airavata_api/js/models/UserConfigurationData.js
index f70ffdf..244d3fb 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/UserConfigurationData.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/UserConfigurationData.js
@@ -27,26 +27,14 @@ const FIELDS = [
type: 'boolean',
default: false,
},
- {
- name: 'userDN',
- type: 'string',
- default: '',
- },
+ 'userDN',
{
name: 'generateCert',
type: 'boolean',
default: false,
},
- {
- name: 'storageId',
- type: 'string',
- default: '',
- },
- {
- name: 'experimentDataDir',
- type: 'string',
- default: '',
- },
+ 'storageId',
+ 'experimentDataDir',
{
name: 'useUserCRPref',
type: 'boolean',
diff --git a/django_airavata/apps/api/thrift_utils.py b/django_airavata/apps/api/thrift_utils.py
index 363a016..30ab400 100644
--- a/django_airavata/apps/api/thrift_utils.py
+++ b/django_airavata/apps/api/thrift_utils.py
@@ -67,20 +67,8 @@ def create_serializer_class(thrift_data_type):
params[field_name] = serializer.create(params[field_name])
return params
- def process_empty_char_fields(self, validated_data):
- """Convert empty CharFields to None."""
- fields = self.fields
- params = copy.deepcopy(validated_data)
- for field_name, serializer in fields.items():
- if isinstance(serializer, CharField) \
- and params.get(field_name, None) is not None \
- and params[field_name].strip() == '':
- params[field_name] = None
- return params
-
def create(self, validated_data):
params = self.process_nested_fields(validated_data)
- params = self.process_empty_char_fields(params)
return thrift_data_type(**params)
def update(self, instance, validated_data):
@@ -103,10 +91,10 @@ def process_field(field, required=False, read_only=False, allow_null=False):
# mapping
field_class = mapping[field[1]]
kwargs = dict(required=required, read_only=read_only)
- # allow_null isn't allowed for BooleanField and we'll use allow_blank
- # for CharField
- if field_class not in (BooleanField, CharField):
+ # allow_null isn't allowed for BooleanField
+ if field_class not in (BooleanField,):
kwargs['allow_null'] = allow_null
+ # allow_null CharField are also allowed to be blank
if field_class == CharField:
kwargs['allow_blank'] = allow_null
return mapping[field[1]](**kwargs)
--
To stop receiving notification emails like this one, please contact
"commits@airavata.apache.org" <co...@airavata.apache.org>.
[airavata-django-portal] 02/04: AIRAVATA-2598 Display validation of
required inputs
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 8615c84ddc84affd5479c8e30191a3b15ab9b2d3
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Thu Jan 11 10:41:24 2018 -0500
AIRAVATA-2598 Display validation of required inputs
---
.../django_airavata_api/js/models/BaseModel.js | 4 ++++
.../js/models/InputDataObjectType.js | 8 ++++++++
.../django_airavata_api/js/models/Project.js | 2 +-
.../js/components/experiment/ExperimentEditor.vue | 22 ++++++++++++++++++++--
4 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
index 9745c90..49f773b 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
@@ -75,6 +75,10 @@ export default class BaseModel {
return null;
}
+ isEmpty(value) {
+ return value === null || (typeof value === 'string' && value.trim() === '');
+ }
+
/**
* Return a fully deep cloned instance of this instance.
*/
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 cf3e349..496de53 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
@@ -37,4 +37,12 @@ export default class InputDataObjectType extends BaseModel {
this.storageResourceId = '';
}
}
+
+ validate() {
+ let results = {};
+ if (this.isRequired && this.isEmpty(this.value)) {
+ results['value'] = 'This field is required.';
+ }
+ return results;
+ }
}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/Project.js b/django_airavata/apps/api/static/django_airavata_api/js/models/Project.js
index d6e9c99..59bc6be 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/Project.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/Project.js
@@ -18,7 +18,7 @@ export default class Project extends BaseModel {
}
validate() {
- if (this.name === null || this.name.trim() === "") {
+ if (this.isEmpty(this.name)) {
return {
name: ["Please provide a name."]
}
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 76040ca..77cbc00 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
@@ -47,9 +47,12 @@
</h2>
<b-form novalidate>
<b-form-group v-for="experimentInput in localExperiment.experimentInputs"
- :label="experimentInput.name" :label-for="experimentInput.name" :key="experimentInput.name">
+ :label="experimentInput.name" :label-for="experimentInput.name" :key="experimentInput.name"
+ :feedback="getApplicationInputFeedback(experimentInput)"
+ :state="getApplicationInputState(experimentInput)">
<b-form-input :id="experimentInput.name" type="text" v-model="experimentInput.value" required
- :placeholder="experimentInput.userFriendlyDescription"></b-form-input>
+ :placeholder="experimentInput.userFriendlyDescription"
+ :state="getApplicationInputState(experimentInput)"></b-form-input>
</b-form-group>
</b-form>
<h2 class="h5 mb-3">
@@ -151,6 +154,21 @@ export default {
console.log("Launch failed!", result);
});
},
+ 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 : null;
+ },
+ getApplicationInputValidation: function(applicationInput) {
+ const validationResults = applicationInput.validate();
+ if (validationResults !== null && 'value' in validationResults) {
+ return validationResults;
+ }
+ return null;
+ }
},
watch: {
experiment: function(newValue) {
--
To stop receiving notification emails like this one, please contact
"commits@airavata.apache.org" <co...@airavata.apache.org>.