708 lines
22 KiB
JavaScript
708 lines
22 KiB
JavaScript
/**
|
|
* Created by tsufiev on 2/24/15.
|
|
*/
|
|
(function() {
|
|
'use strict';
|
|
|
|
angular.module('mistral')
|
|
.factory('mistral.workbook.models',
|
|
['merlin.field.models', 'merlin.panel.models', 'merlin.utils', '$http', '$q',
|
|
function(fields, panel, utils, $http, $q) {
|
|
var models = {};
|
|
|
|
function varlistValueFactory(json, parameters) {
|
|
var type = Barricade.getType(json);
|
|
if ( json === undefined || type === String ) {
|
|
return fields.string.create(json, parameters);
|
|
} else if ( type === Array ) {
|
|
return fields.list.extend({}, {
|
|
'*': {'@class': fields.string}
|
|
}).create(json, parameters);
|
|
} else if ( type === Object ) {
|
|
return fields.dictionary.extend({}, {
|
|
'?': {'@class': fields.string}
|
|
}).create(json, parameters);
|
|
}
|
|
}
|
|
|
|
models.varlist = fields.list.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.list.create.call(this, json, parameters);
|
|
self.setType('varlist');
|
|
self.on('childChange', function(child, op) {
|
|
if ( op == 'empty' ) {
|
|
self.each(function(index, item) {
|
|
if ( child === item ) {
|
|
self.remove(index);
|
|
}
|
|
})
|
|
}
|
|
});
|
|
return self;
|
|
}
|
|
}, {
|
|
'*': {
|
|
'@class': fields.frozendict.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.frozendict.create.call(this, json, parameters);
|
|
self.on('childChange', function(child) {
|
|
if ( child.instanceof(Barricade.Enumerated) ) { // type change
|
|
var value = self.get('value');
|
|
switch ( child.get() ) {
|
|
case 'string':
|
|
self.set('value', varlistValueFactory(''));
|
|
break;
|
|
case 'list':
|
|
self.set('value', varlistValueFactory(['']));
|
|
break;
|
|
case 'dictionary':
|
|
self.set('value', varlistValueFactory({'key1': ''}));
|
|
break;
|
|
}
|
|
} else if ( child.instanceof(Barricade.Arraylike) && !child.length() ) {
|
|
self.emit('change', 'empty');
|
|
}
|
|
});
|
|
return self;
|
|
},
|
|
_getPrettyJSON: function() {
|
|
var json = fields.frozendict._getPrettyJSON.apply(this, arguments);
|
|
return json.value;
|
|
}
|
|
}, {
|
|
'type': {
|
|
'@class': fields.string.extend({}, {
|
|
'@enum': ['string', 'list', 'dictionary'],
|
|
'@default': 'string'
|
|
})
|
|
},
|
|
'value': {
|
|
'@class': fields.wildcard,
|
|
'@factory': varlistValueFactory
|
|
}
|
|
})
|
|
}
|
|
});
|
|
|
|
models.yaqllist = fields.list.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.list.create.call(this, json, parameters);
|
|
self.setType('yaqllist');
|
|
return self;
|
|
}
|
|
}, {
|
|
'*': {
|
|
'@class': fields.frozendict.extend({}, {
|
|
'yaql': {
|
|
'@class': fields.string
|
|
},
|
|
'action': {
|
|
'@class': fields.string
|
|
}
|
|
})
|
|
}
|
|
});
|
|
|
|
models.Action = fields.frozendict.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.frozendict.create.call(this, json, parameters),
|
|
base = self.get('base');
|
|
base.on('change', function(operation) {
|
|
var baseValue;
|
|
if ( operation != 'id' ) {
|
|
baseValue = base.get();
|
|
if ( baseValue ) {
|
|
base.getSchema(baseValue).then(function(keys) {
|
|
self.get('base-input').setSchema(keys);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
return self;
|
|
}
|
|
}, {
|
|
'base': {
|
|
'@class': fields.string.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.string.create.call(this, json, parameters),
|
|
schema = {},
|
|
url = utils.getMeta(self, 'autocompletionUrl');
|
|
|
|
self.getSchema = function(key) {
|
|
var deferred = $q.defer();
|
|
if ( !(key in schema) ) {
|
|
$http.get(url+'?key='+key).success(function(keys) {
|
|
schema[key] = keys;
|
|
deferred.resolve(keys);
|
|
}).error(function() {
|
|
deferred.reject();
|
|
});
|
|
} else {
|
|
deferred.resolve(schema[key]);
|
|
}
|
|
return deferred.promise;
|
|
};
|
|
return self;
|
|
}
|
|
}, {
|
|
'@meta': {
|
|
'index': 1,
|
|
'row': 0,
|
|
'autocompletionUrl': '/project/mistral/actions/types'
|
|
}
|
|
})
|
|
},
|
|
'base-input': {
|
|
'@class': fields.directeddictionary.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 2,
|
|
'title': 'Base Input'
|
|
},
|
|
'?': {
|
|
'@class': fields.string.extend({}, {
|
|
'@meta': {'row': 1}
|
|
})
|
|
}
|
|
})
|
|
},
|
|
'input': {
|
|
'@class': fields.list.extend({}, {
|
|
'@meta': {
|
|
'index': 3
|
|
},
|
|
'*': {'@class': fields.string}
|
|
})
|
|
},
|
|
'output': {
|
|
'@class': models.varlist.extend({}, {
|
|
'@meta': {
|
|
'index': 4
|
|
}
|
|
})
|
|
}
|
|
});
|
|
|
|
models.Task = fields.frozendict.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.frozendict.create.call(this, json, parameters);
|
|
self.on('childChange', function(child, op) {
|
|
if ( child === self.get('type') && op !== 'id' ) {
|
|
self.emit('change', 'taskType');
|
|
}
|
|
});
|
|
return self;
|
|
},
|
|
remove: function() {
|
|
this.emit('change', 'taskRemove', this.getID());
|
|
},
|
|
_getPrettyJSON: function() {
|
|
var json = fields.frozendict._getPrettyJSON.apply(this, arguments);
|
|
delete json.type;
|
|
return json;
|
|
}
|
|
}, {
|
|
'@meta': {
|
|
'baseKey': 'task',
|
|
'baseName': 'Task ',
|
|
'group': true,
|
|
'additive': false,
|
|
'removable': true
|
|
},
|
|
'type': {
|
|
'@class': fields.string.extend({}, {
|
|
'@enum': [{
|
|
value: 'action', label: 'Action-based'
|
|
}, {
|
|
value: 'workflow', label: 'Workflow-based'
|
|
}],
|
|
'@default': 'action',
|
|
'@meta': {
|
|
'index': 0,
|
|
'row': 0
|
|
}
|
|
})
|
|
},
|
|
'description': {
|
|
'@class': fields.text.extend({}, {
|
|
'@meta': {
|
|
'index': 2,
|
|
'row': 1
|
|
}
|
|
})
|
|
},
|
|
'input': {
|
|
'@class': fields.dictionary.extend({}, {
|
|
'@meta': {
|
|
'index': 4
|
|
},
|
|
'?': {
|
|
'@class': fields.string
|
|
}
|
|
})
|
|
},
|
|
'publish': {
|
|
'@class': fields.dictionary.extend({}, {
|
|
'@meta': {
|
|
'index': 5
|
|
},
|
|
'?': {
|
|
'@class': fields.string
|
|
}
|
|
})
|
|
},
|
|
'policies': {
|
|
'@class': fields.frozendict.extend({
|
|
_getPrettyJSON: function() {
|
|
var json = fields.frozendict._getPrettyJSON.apply(this, arguments);
|
|
json.retry = {
|
|
count: utils.pop(json, 'retry-count'),
|
|
delay: utils.pop(json, 'retry-delay'),
|
|
'break-on': utils.pop(json, 'retry-break-on')
|
|
};
|
|
return json;
|
|
}
|
|
}, {
|
|
'@meta': {
|
|
'index': 9
|
|
},
|
|
'@required': false,
|
|
'wait-before': {
|
|
'@class': fields.number.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 0,
|
|
'row': 0,
|
|
'title': 'Wait before'
|
|
}
|
|
})
|
|
},
|
|
'wait-after': {
|
|
'@class': fields.number.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 1,
|
|
'row': 0,
|
|
'title': 'Wait after'
|
|
}
|
|
})
|
|
},
|
|
'timeout': {
|
|
'@class': fields.number.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 2,
|
|
'row': 1
|
|
}
|
|
})
|
|
},
|
|
'retry-count': {
|
|
'@class': fields.number.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 3,
|
|
'row': 2,
|
|
'title': 'Retry count'
|
|
}
|
|
})
|
|
},
|
|
'retry-delay': {
|
|
'@class': fields.number.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 4,
|
|
'row': 2,
|
|
'title': 'Retry delay'
|
|
}
|
|
})
|
|
},
|
|
'retry-break-on': {
|
|
'@class': fields.number.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 5,
|
|
'row': 3,
|
|
'title': 'Retry break on'
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
});
|
|
|
|
models.ReverseWFTask = models.Task.extend({}, {
|
|
'requires': {
|
|
'@class': fields.string.extend({}, {
|
|
'@meta': {
|
|
'row': 2,
|
|
'index': 3
|
|
}
|
|
})
|
|
}
|
|
});
|
|
|
|
models.DirectWFTask = models.Task.extend({}, {
|
|
'on-error': {
|
|
'@class': fields.list.extend({}, {
|
|
'@meta': {
|
|
'title': 'On error',
|
|
'index': 6
|
|
},
|
|
'*': {
|
|
'@class': fields.string
|
|
}
|
|
})
|
|
},
|
|
'on-success': {
|
|
'@class': fields.list.extend({}, {
|
|
'@meta': {
|
|
'title': 'On success',
|
|
'index': 7
|
|
},
|
|
'*': {
|
|
'@class': fields.string
|
|
}
|
|
})
|
|
},
|
|
'on-complete': {
|
|
'@class': fields.list.extend({}, {
|
|
'@meta': {
|
|
'title': 'On complete',
|
|
'index': 8
|
|
},
|
|
'*': {
|
|
'@class': fields.string
|
|
}
|
|
})
|
|
}
|
|
});
|
|
|
|
models.ActionTaskMixin = Barricade.Blueprint.create(function() {
|
|
return this.extend({}, {
|
|
'action': {
|
|
'@class': fields.string.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.string.create.call(this, json, parameters),
|
|
actionsCls = Barricade.create({
|
|
'@type': String,
|
|
'@ref': {
|
|
to: function() {
|
|
return models.Actions;
|
|
},
|
|
needs: function() {
|
|
return models.Workbook;
|
|
},
|
|
getter: function(data) {
|
|
return data.needed.get('actions');
|
|
}
|
|
}
|
|
});
|
|
|
|
self._actions = actionsCls.create().on(
|
|
'replace', function(newValue) {
|
|
self._actions = newValue;
|
|
self._actions.on('change', function() {
|
|
self._choices = self._actions.getIDs();
|
|
self.resetValues();
|
|
});
|
|
self._actions.emit('change');
|
|
});
|
|
return self;
|
|
},
|
|
_choices: null
|
|
}, {
|
|
'@enum': function() {
|
|
if (!this._choices) {
|
|
this._choices = [];
|
|
this.emit('_resolveUp', this._actions);
|
|
}
|
|
return this._choices;
|
|
},
|
|
'@meta': {
|
|
'row': 0,
|
|
'index': 1
|
|
}
|
|
})
|
|
}
|
|
})
|
|
});
|
|
|
|
models.WorkflowTaskMixin = Barricade.Blueprint.create(function() {
|
|
return this.extend({}, {
|
|
'workflow': {
|
|
'@class': fields.string.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.string.create.call(this, json, parameters),
|
|
workflowsCls = Barricade.create({
|
|
'@type': String,
|
|
'@ref': {
|
|
to: function() {
|
|
return models.Workflows;
|
|
},
|
|
needs: function() {
|
|
return models.Workbook;
|
|
},
|
|
getter: function(data) {
|
|
return data.needed.get('workflows');
|
|
}
|
|
}
|
|
});
|
|
|
|
self._workflows = workflowsCls.create().on(
|
|
'replace', function(newValue) {
|
|
self._workflows = newValue;
|
|
self._workflows.on('change', function() {
|
|
self._choices = self._workflows.getIDs();
|
|
self.resetValues();
|
|
});
|
|
self._workflows.emit('change');
|
|
});
|
|
return self;
|
|
},
|
|
_choices: null
|
|
}, {
|
|
'@enum': function() {
|
|
if ( !this._choices ) {
|
|
this._choices = [];
|
|
this.emit('_resolveUp', this._workflows);
|
|
}
|
|
return this._choices;
|
|
},
|
|
'@meta': {
|
|
'row': 0,
|
|
'index': 1
|
|
}
|
|
})
|
|
}
|
|
});
|
|
});
|
|
|
|
var taskTypes = {
|
|
'direct': models.DirectWFTask,
|
|
'reverse': models.ReverseWFTask,
|
|
'action': models.ActionTaskMixin,
|
|
'workflow': models.WorkflowTaskMixin
|
|
};
|
|
|
|
function TaskFactory(json, parameters) {
|
|
var type = json.type || 'action',
|
|
baseClass = taskTypes[parameters.wfType],
|
|
mixinClass = taskTypes[type],
|
|
taskClass = mixinClass.call(baseClass);
|
|
return taskClass.create(json, parameters);
|
|
}
|
|
|
|
models.Workflow = fields.frozendict.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.frozendict.create.call(this, json, parameters);
|
|
self.on('childChange', function(child, op) {
|
|
if ( child === self.get('type') && op !== 'id' ) {
|
|
self.emit('change', 'workflowType');
|
|
}
|
|
});
|
|
return self;
|
|
}
|
|
}, {
|
|
'type': {
|
|
'@class': fields.string.extend({}, {
|
|
'@enum': ['reverse', 'direct'],
|
|
'@default': 'direct',
|
|
'@meta': {
|
|
'index': 1,
|
|
'row': 0
|
|
}
|
|
})
|
|
},
|
|
'input': {
|
|
'@class': fields.list.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 2
|
|
},
|
|
'*': {
|
|
'@class': fields.string
|
|
}
|
|
})
|
|
},
|
|
'output': {
|
|
'@class': fields.list.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 3
|
|
},
|
|
'*': {
|
|
'@class': fields.string
|
|
}
|
|
})
|
|
},
|
|
'tasks': {
|
|
'@class': fields.dictionary.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.dictionary.create.call(this, json, parameters);
|
|
self.on('childChange', function(child, op, arg) {
|
|
if ( op === 'taskType' ) {
|
|
var taskId = child.getID(),
|
|
params = child._parameters,
|
|
taskPos = self.getPosByID(taskId),
|
|
taskData = child.toJSON();
|
|
params.id = taskId;
|
|
self.set(taskPos, TaskFactory(taskData, params));
|
|
} else if ( op === 'taskRemove' ) {
|
|
self.remove(arg);
|
|
}
|
|
});
|
|
return self;
|
|
}
|
|
}, {
|
|
'@meta': {
|
|
'index': 5,
|
|
'group': true
|
|
},
|
|
'?': {
|
|
'@class': models.Task,
|
|
'@factory': TaskFactory
|
|
}
|
|
})
|
|
}
|
|
|
|
});
|
|
|
|
models.ReverseWorkflow = models.Workflow.extend({});
|
|
models.DirectWorkflow = models.Workflow.extend({}, {
|
|
'task-defaults': {
|
|
'@class': fields.frozendict.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 4,
|
|
'group': true,
|
|
'additive': false
|
|
},
|
|
'on-error': {
|
|
'@class': models.yaqllist.extend({}, {
|
|
'@meta': {
|
|
'title': 'On error',
|
|
'index': 0
|
|
}
|
|
})
|
|
},
|
|
'on-success': {
|
|
'@class': models.yaqllist.extend({}, {
|
|
'@meta': {
|
|
'title': 'On success',
|
|
'index': 1
|
|
}
|
|
})
|
|
},
|
|
'on-complete': {
|
|
'@class': models.yaqllist.extend({}, {
|
|
'@meta': {
|
|
'title': 'On complete',
|
|
'index': 2
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
});
|
|
|
|
var workflowTypes = {
|
|
'direct': models.DirectWorkflow,
|
|
'reverse': models.ReverseWorkflow
|
|
};
|
|
|
|
function workflowFactory(json, parameters) {
|
|
var type = json.type || 'direct';
|
|
parameters.wfType = type;
|
|
return workflowTypes[type].create(json, parameters);
|
|
}
|
|
|
|
models.Actions = fields.dictionary.extend({}, {
|
|
'@required': false,
|
|
'@meta': {
|
|
'index': 3,
|
|
'panelIndex': 1
|
|
},
|
|
'?': {
|
|
'@class': models.Action
|
|
}
|
|
});
|
|
|
|
models.Workflows = fields.dictionary.extend({
|
|
create: function(json, parameters) {
|
|
var self = fields.dictionary.create.call(this, json, parameters);
|
|
self.on('childChange', function(child, op) {
|
|
if ( op === 'workflowType' ) {
|
|
var workflowId = child.getID(),
|
|
workflowPos = self.getPosByID(workflowId),
|
|
params = child._parameters,
|
|
workflowData = child.toJSON();
|
|
params.wfType = child.type;
|
|
params.id = workflowId;
|
|
self.set(workflowPos, workflowFactory(workflowData, params));
|
|
}
|
|
});
|
|
return self;
|
|
}
|
|
}, {
|
|
'@meta': {
|
|
'index': 4,
|
|
'panelIndex': 2
|
|
},
|
|
'?': {
|
|
'@class': models.Workflow,
|
|
'@factory': workflowFactory
|
|
}
|
|
});
|
|
|
|
models.Workbook = fields.frozendict.extend({
|
|
toYAML: function() {
|
|
return jsyaml.dump(this.toJSON({pretty: true}));
|
|
}
|
|
}, {
|
|
'version': {
|
|
'@class': fields.string.extend({}, {
|
|
'@enum': ['2.0'],
|
|
'@meta': {
|
|
'index': 2,
|
|
'panelIndex': 0,
|
|
'row': 1
|
|
},
|
|
'@default': '2.0'
|
|
})
|
|
},
|
|
'name': {
|
|
'@class': fields.string.extend({}, {
|
|
'@meta': {
|
|
'index': 0,
|
|
'panelIndex': 0,
|
|
'row': 0
|
|
},
|
|
'@constraints': [
|
|
function(value) {
|
|
return value !== 'workbook1' ? true : 'The sample validation failure.';
|
|
}
|
|
]
|
|
})
|
|
},
|
|
'description': {
|
|
'@class': fields.text.extend({}, {
|
|
'@meta': {
|
|
'index': 1,
|
|
'panelIndex': 0,
|
|
'row': 0
|
|
},
|
|
'@required': false
|
|
})
|
|
},
|
|
'actions': {
|
|
'@class': models.Actions
|
|
},
|
|
'workflows': {
|
|
'@class': models.Workflows
|
|
}
|
|
});
|
|
|
|
return models;
|
|
}])
|
|
})();
|