Move an entire workbook to schema
This is a preparation for integrating with Barricade.js Change-Id: Iba9424ddc8337497d5bb8431c114b1b07902f6b8
This commit is contained in:
parent
b408d89815
commit
b922fad15b
|
@ -9,3 +9,6 @@ ADD_INSTALLED_APPS = ['merlin', 'mistral']
|
||||||
|
|
||||||
# Python panel class of the PANEL to be added.
|
# Python panel class of the PANEL to be added.
|
||||||
ADD_PANEL = 'mistral.panel.MistralPanel'
|
ADD_PANEL = 'mistral.panel.MistralPanel'
|
||||||
|
|
||||||
|
ADD_ANGULAR_MODULES = ['angular.filter']
|
||||||
|
ADD_JS_FILES = ['merlin/lib/angular-filter.js']
|
|
@ -1,10 +1,16 @@
|
||||||
<div class="panel panel-default merlin-panel">
|
<div class="panel panel-default merlin-panel">
|
||||||
<div class="panel-heading">
|
<div ng-if="title">
|
||||||
<h4 class="panel-title">
|
<div class="panel-heading">
|
||||||
<a data-toggle="collapse" data-target="#elem-{$ $id $}" href="#">{$ title $}</a>
|
<h4 class="panel-title">
|
||||||
<a href="#" ng-click="removable()"><i ng-show="removable" class="fa fa-times-circle pull-right"></i></a></h4>
|
<a data-toggle="collapse" data-target="#elem-{$ $id $}" href="#">{$ title $}</a>
|
||||||
|
<a href="#" ng-click="onRemove()"><i ng-show="removable" class="fa fa-times-circle pull-right"></i></a></h4>
|
||||||
|
</div>
|
||||||
|
<div id="elem-{$ $id $}" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body" ng-transclude>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="elem-{$ $id $}" class="panel-collapse collapse in">
|
<div ng-if="!title">
|
||||||
<div class="panel-body" ng-transclude>
|
<div class="panel-body" ng-transclude>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
<div class="three-columns" ng-repeat="(key, value) in item[spec.name] track by key">
|
<collapsible-group title="{$ spec.title || makeTitle(spec.name) $}" on-add="add(item[spec.name], '')">
|
||||||
<div class="left-column">
|
<div class="three-columns" ng-repeat="(key, value) in item[spec.name] track by key">
|
||||||
<div class="form-group">
|
<div class="left-column">
|
||||||
<label for="elem-{$ $id $}.{$ key $}">
|
<div class="form-group">
|
||||||
<editable value="key" label="New Name"></editable>
|
<label for="elem-{$ $id $}.{$ key $}">
|
||||||
</label>
|
<editable value="key" label="New Name"></editable>
|
||||||
<div class="input-group">
|
</label>
|
||||||
<input id="elem-{$ $id $}.{$ key $}" type="text" class="form-control" ng-model="value">
|
<div class="input-group">
|
||||||
<i class="fa fa-minus-circle input-group-addon"></i>
|
<input id="elem-{$ $id $}.{$ key $}" type="text" class="form-control" ng-model="value">
|
||||||
|
<i class="fa fa-minus-circle input-group-addon"></i>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</collapsible-group>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<collapsible-group title="{$ spec.title || makeTitle(spec.name) $}" additive="false">
|
<collapsible-group title="{$ spec.title || makeTitle(spec.name) $}">
|
||||||
<div class="three-columns">
|
<div class="three-columns">
|
||||||
<div class="left-column">
|
<div class="left-column">
|
||||||
<div class="form-group" ng-repeat="(key, item) in item[spec.name] track by key">
|
<div class="form-group" ng-repeat="(key, item) in item[spec.name] track by key">
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<collapsible-group title="{$ spec.title || makeTitle(spec.name) $}" on-add="add(item[spec.name])">
|
||||||
|
<div ng-repeat="specs in spec.value | groupBy: 'row' | toArray: true | orderBy: '$key' track by specs.$key">
|
||||||
|
<div ng-class="{'three-columns': specs[0].row !== undefined }">
|
||||||
|
<div ng-repeat="spec in specs track by spec.name"
|
||||||
|
ng-class="{'right-column': $odd && isAtomic(spec.type), 'left-column': $even && isAtomic(spec.type)}">
|
||||||
|
<typed-field></typed-field>
|
||||||
|
<div class="clearfix" ng-show="$odd"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</collapsible-group>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="elem-{$ $id $}">{$ spec.title || makeTitle(spec.name) $}</label>
|
||||||
|
<textarea class="form-control" id="elem-{$ $id $}" ng-model="item[spec.name]"></textarea>
|
||||||
|
</div>
|
|
@ -1,4 +1,5 @@
|
||||||
<collapsible-group title="{$ spec.title || makeTitle(spec.name) $}" on-add="add(item[spec.name], {type: 'string', value: '', id: 'varlist'+item[spec.name].length})">
|
<collapsible-group title="{$ spec.title || makeTitle(spec.name) $}"
|
||||||
|
on-add="add(item[spec.name], {type: 'string', value: '', id: 'varlist'+item[spec.name].length})">
|
||||||
<div class="three-columns" ng-repeat="subItem in item[spec.name] track by subItem.id"
|
<div class="three-columns" ng-repeat="subItem in item[spec.name] track by subItem.id"
|
||||||
ng-class="{dictionary: subItem.type == 'dictionary', list: subItem.type == 'list'}">
|
ng-class="{dictionary: subItem.type == 'dictionary', list: subItem.type == 'list'}">
|
||||||
<div class="left-column">
|
<div class="left-column">
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<collapsible-group title="{$ spec.title || makeTitle(spec.name) $}" on-add="add(item[spec.name], '')">
|
||||||
|
<div class="three-columns">
|
||||||
|
<div class="left-column" style="display:none">
|
||||||
|
<div class="form-group">
|
||||||
|
<textarea class="form-control">{$ yaqlExpresion $}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right-column">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon yaql-condition fa fa-unlock" role="button"></span>
|
||||||
|
<input type="text" class="form-control" value="{$ value $}">
|
||||||
|
<span class="input-group-addon fa fa-minus-circle"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</collapsible-group>
|
|
@ -65,33 +65,219 @@
|
||||||
type: 'list',
|
type: 'list',
|
||||||
value: ['', '']
|
value: ['', '']
|
||||||
}]
|
}]
|
||||||
}
|
}],
|
||||||
]
|
workflows: [{
|
||||||
|
id: 'workflow1',
|
||||||
|
name: 'Workflow1',
|
||||||
|
base: '', // FIXME
|
||||||
|
input: [''],
|
||||||
|
output: [{
|
||||||
|
id: 'varlist1',
|
||||||
|
type: 'string',
|
||||||
|
value: ''
|
||||||
|
}],
|
||||||
|
taskDefaults: {
|
||||||
|
onError: {
|
||||||
|
type: 'list',
|
||||||
|
value: ['', '']
|
||||||
|
},
|
||||||
|
onSuccess: {
|
||||||
|
type: 'list',
|
||||||
|
value: ['']
|
||||||
|
},
|
||||||
|
onComplete: {
|
||||||
|
type: 'list',
|
||||||
|
value: ['', '']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.schema = {
|
$scope.schema = {
|
||||||
action: [{
|
name: {
|
||||||
name: 'name',
|
|
||||||
type: 'string',
|
type: 'string',
|
||||||
group: 'one'
|
index: 0,
|
||||||
}, {
|
panelIndex: 0,
|
||||||
name: 'base',
|
row: 0
|
||||||
type: 'string',
|
},
|
||||||
group: 'one'
|
description: {
|
||||||
}, {
|
type: 'text',
|
||||||
name: 'baseInput',
|
index: 1,
|
||||||
type: 'frozendict',
|
panelIndex: 0,
|
||||||
group: ''
|
row: 0
|
||||||
}, {
|
},
|
||||||
name: 'input',
|
actions: {
|
||||||
type: 'list',
|
index: 2,
|
||||||
group: ''
|
type: 'panel',
|
||||||
}, {
|
multiple: true,
|
||||||
name: 'output',
|
value: {
|
||||||
type: 'varlist',
|
name: {
|
||||||
group: ''
|
type: 'string',
|
||||||
|
row: 0,
|
||||||
|
index: 0
|
||||||
|
},
|
||||||
|
base: {
|
||||||
|
type: 'string',
|
||||||
|
row: 0,
|
||||||
|
index: 1
|
||||||
|
},
|
||||||
|
baseInput: {
|
||||||
|
type: 'frozendict',
|
||||||
|
title: 'Base Input',
|
||||||
|
index: 2
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
type: 'list',
|
||||||
|
index: 3
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
type: 'varlist',
|
||||||
|
index: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
workflows: {
|
||||||
|
index: 3,
|
||||||
|
type: 'panel',
|
||||||
|
multiple: true,
|
||||||
|
value: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
index: 0,
|
||||||
|
row: 0
|
||||||
|
},
|
||||||
|
base: {
|
||||||
|
type: 'string',
|
||||||
|
index: 1,
|
||||||
|
row: 0
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
type: 'list',
|
||||||
|
index: 2
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
type: 'varlist',
|
||||||
|
index: 3
|
||||||
|
},
|
||||||
|
taskDefaults: {
|
||||||
|
type: 'group',
|
||||||
|
title: 'Task defaults',
|
||||||
|
additive: false,
|
||||||
|
index: 4,
|
||||||
|
value: {
|
||||||
|
onError: {
|
||||||
|
type: 'yaqllist',
|
||||||
|
title: 'On error',
|
||||||
|
index: 0
|
||||||
|
},
|
||||||
|
onSuccess: {
|
||||||
|
type: 'yaqllist',
|
||||||
|
title: 'On success',
|
||||||
|
index: 1
|
||||||
|
},
|
||||||
|
onComplete: {
|
||||||
|
type: 'yaqllist',
|
||||||
|
title: 'On complete',
|
||||||
|
index: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tasks: {
|
||||||
|
type: 'group',
|
||||||
|
index: 5,
|
||||||
|
value: {
|
||||||
|
task: {
|
||||||
|
type: 'group',
|
||||||
|
additive: false,
|
||||||
|
multiple: true,
|
||||||
|
index: 0,
|
||||||
|
value: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
index: 0,
|
||||||
|
row: 0
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
index: 1,
|
||||||
|
row: 0
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: 'string',
|
||||||
|
index: 2,
|
||||||
|
row: 1
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
type: 'dictionary',
|
||||||
|
index: 3
|
||||||
|
},
|
||||||
|
publish: {
|
||||||
|
type: 'dictionary',
|
||||||
|
index: 4
|
||||||
|
},
|
||||||
|
onError: {
|
||||||
|
type: 'yaqllist',
|
||||||
|
title: 'On error',
|
||||||
|
index: 5
|
||||||
|
},
|
||||||
|
onSuccess: {
|
||||||
|
type: 'yaqllist',
|
||||||
|
title: 'On success',
|
||||||
|
index: 6
|
||||||
|
},
|
||||||
|
onComplete: {
|
||||||
|
type: 'yaqllist',
|
||||||
|
title: 'On complete',
|
||||||
|
index: 7
|
||||||
|
},
|
||||||
|
policies: {
|
||||||
|
type: 'group',
|
||||||
|
additive: false,
|
||||||
|
index: 8,
|
||||||
|
value: {
|
||||||
|
waitBefore: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Wait before',
|
||||||
|
index: 0,
|
||||||
|
row: 0
|
||||||
|
},
|
||||||
|
waitAfter: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Wait after',
|
||||||
|
index: 1,
|
||||||
|
row: 0
|
||||||
|
},
|
||||||
|
timeout: {
|
||||||
|
type: 'string',
|
||||||
|
index: 2,
|
||||||
|
row: 1
|
||||||
|
},
|
||||||
|
retryCount: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Retry count',
|
||||||
|
index: 3,
|
||||||
|
row: 2
|
||||||
|
},
|
||||||
|
retryDelay: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Retry delay',
|
||||||
|
index: 4,
|
||||||
|
row: 2
|
||||||
|
},
|
||||||
|
retryBreakOn: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Retry break on',
|
||||||
|
index: 5,
|
||||||
|
row: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.makeTitle = function(str) {
|
$scope.makeTitle = function(str) {
|
||||||
|
@ -107,7 +293,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.isAtomic = function(type) {
|
$scope.isAtomic = function(type) {
|
||||||
return ['string'].indexOf(type) > -1;
|
return ['string', 'text'].indexOf(type) > -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.remove = function(parent, item) {
|
$scope.remove = function(parent, item) {
|
||||||
|
|
|
@ -60,22 +60,25 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
.directive('collapsiblePanel', function($parse, defaultSetter) {
|
.directive('panel', function() {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
templateUrl: '/static/mistral/js/angular-templates/collapsible-panel.html',
|
templateUrl: '/static/mistral/js/angular-templates/collapsible-panel.html',
|
||||||
transclude: true,
|
transclude: true,
|
||||||
scope: {
|
scope: {
|
||||||
title: '@',
|
title: '@',
|
||||||
removable: '&'
|
onRemove: '&'
|
||||||
},
|
},
|
||||||
link: function(scope, element, attrs) {
|
link: function(scope, element, attrs) {
|
||||||
disableClickDefaultBehaviour(element);
|
disableClickDefaultBehaviour(element);
|
||||||
|
if ( attrs.onRemove ) {
|
||||||
|
scope.removable = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
.directive('collapsibleGroup', function($parse, defaultSetter) {
|
.directive('collapsibleGroup', function() {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
templateUrl: '/static/mistral/js/angular-templates/collapsible-group.html',
|
templateUrl: '/static/mistral/js/angular-templates/collapsible-group.html',
|
||||||
|
|
|
@ -1,324 +1,329 @@
|
||||||
|
|
||||||
/* Copyright (c) 2014 Mirantis, Inc.
|
/* Copyright (c) 2014 Mirantis, Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
not use this file except in compliance with the License. You may obtain
|
not use this file except in compliance with the License. You may obtain
|
||||||
a copy of the License at
|
a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
License for the specific language governing permissions and limitations
|
License for the specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var types = {
|
var types = {
|
||||||
Mistral: {},
|
Mistral: {},
|
||||||
base: {},
|
base: {},
|
||||||
OpenStack: {
|
OpenStack: {
|
||||||
// TODO: obtain list of predefined OpenStack actions from Mistral server-side
|
// TODO: obtain list of predefined OpenStack actions from Mistral server-side
|
||||||
// for now a stubbed list of predefined actions suffices
|
// for now a stubbed list of predefined actions suffices
|
||||||
actions: ['createInstance', 'terminateInstance']
|
actions: ['createInstance', 'terminateInstance']
|
||||||
},
|
},
|
||||||
getOpenStackActions: function() {
|
getOpenStackActions: function() {
|
||||||
return this.OpenStack.actions.slice();
|
return this.OpenStack.actions.slice();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
types.base.AcceptsMixin = Barricade.Blueprint.create(function (acceptsList) {
|
types.base.AcceptsMixin = Barricade.Blueprint.create(function (acceptsList) {
|
||||||
acceptsList = acceptsList || [];
|
acceptsList = acceptsList || [];
|
||||||
|
|
||||||
this.getLabels = function() {
|
this.getLabels = function() {
|
||||||
return acceptsList.map(function(item) {
|
return acceptsList.map(function(item) {
|
||||||
return item.label;
|
return item.label;
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getValue = function(label) {
|
this.getValue = function(label) {
|
||||||
for ( var i = 0; i < acceptsList.length; i++ ) {
|
for ( var i = 0; i < acceptsList.length; i++ ) {
|
||||||
if ( acceptsList[i].label === label ) {
|
if ( acceptsList[i].label === label ) {
|
||||||
return acceptsList[i].value;
|
return acceptsList[i].value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
types.Mistral.Action = Barricade.create({
|
types.Mistral.Action = Barricade.create({
|
||||||
'@type': Object,
|
'@type': Object,
|
||||||
|
'@meta': {'groups': ['panel2']},
|
||||||
|
|
||||||
'name': {'@type': String},
|
'name': {'@type': String},
|
||||||
'base': {
|
'base': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@enum': function() {
|
'@enum': function() {
|
||||||
var predefinedActions = types.getOpenStackActions(),
|
var predefinedActions = types.getOpenStackActions(),
|
||||||
actions = workbook.get('actions'),
|
actions = workbook.get('actions'),
|
||||||
currentItemIndex = actions.length() - 1;
|
currentItemIndex = actions.length() - 1;
|
||||||
actions.each(function(index, actionItem) {
|
actions.each(function(index, actionItem) {
|
||||||
var name = actionItem.get('name');
|
var name = actionItem.get('name');
|
||||||
if ( index < currentItemIndex && !name.isEmpty() ) {
|
if ( index < currentItemIndex && !name.isEmpty() ) {
|
||||||
predefinedActions = predefinedActions.concat(name.get())
|
predefinedActions = predefinedActions.concat(name.get())
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return predefinedActions;
|
return predefinedActions;
|
||||||
},
|
},
|
||||||
'@default': types.getOpenStackActions()[0]
|
'@default': types.getOpenStackActions()[0]
|
||||||
},
|
},
|
||||||
'base-input': {
|
'base-input': {
|
||||||
'@type': Object,
|
'@type': Object,
|
||||||
'@required': false,
|
'@required': false,
|
||||||
'?': {'@type': String}
|
'?': {'@type': String}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
types.Mistral.Policy = Barricade.create({
|
types.Mistral.Policy = Barricade.create({
|
||||||
'@type': Object,
|
'@type': Object,
|
||||||
|
|
||||||
'wait-before': {
|
'wait-before': {
|
||||||
'@type': Number,
|
'@type': Number,
|
||||||
'@required': false
|
'@required': false
|
||||||
},
|
},
|
||||||
'wait-after': {
|
'wait-after': {
|
||||||
'@type': Number,
|
'@type': Number,
|
||||||
'@required': false
|
'@required': false
|
||||||
},
|
},
|
||||||
'retry': {
|
'retry': {
|
||||||
'@type': Object,
|
'@type': Object,
|
||||||
'@required': false,
|
'@required': false,
|
||||||
'count': {'@type': Number},
|
'count': {'@type': Number},
|
||||||
'delay': {'@type': Number},
|
'delay': {'@type': Number},
|
||||||
'break-on': {
|
'break-on': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@required': false
|
'@required': false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'timeout': {
|
'timeout': {
|
||||||
'@type': Number,
|
'@type': Number,
|
||||||
'@required': false
|
'@required': false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
types.Mistral.Task = Barricade.create({
|
types.Mistral.Task = Barricade.create({
|
||||||
'@type': Object,
|
'@type': Object,
|
||||||
|
|
||||||
'name': {'@type': String},
|
'name': {'@type': String},
|
||||||
'input': {
|
'input': {
|
||||||
'@type': Array,
|
'@type': Array,
|
||||||
'*': {
|
'*': {
|
||||||
'@class': Barricade.Primitive.extend({
|
'@class': Barricade.Primitive.extend({
|
||||||
'name': 'Parameter'
|
'name': 'Parameter'
|
||||||
}, {
|
}, {
|
||||||
'@type': String
|
'@type': String
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'publish': {
|
'publish': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@required': false
|
'@required': false
|
||||||
},
|
},
|
||||||
'policies': {
|
'policies': {
|
||||||
'@class': types.Mistral.Policy,
|
'@class': types.Mistral.Policy,
|
||||||
'@required': false
|
'@required': false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
types.Mistral.Tasks = Barricade.MutableObject.extend({
|
types.Mistral.Tasks = Barricade.MutableObject.extend({
|
||||||
create: function(json, parameters) {
|
create: function(json, parameters) {
|
||||||
var self = Barricade.MutableObject.create.call(this);
|
var self = Barricade.MutableObject.create.call(this);
|
||||||
|
|
||||||
function getParentWorkflowType() {
|
function getParentWorkflowType() {
|
||||||
var container = self._container,
|
var container = self._container,
|
||||||
workflow;
|
workflow;
|
||||||
while ( container ) {
|
while ( container ) {
|
||||||
if ( container.instanceof(types.Mistral.Workflow) ) {
|
if ( container.instanceof(types.Mistral.Workflow) ) {
|
||||||
workflow = container;
|
workflow = container;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
container = container._container;
|
container = container._container;
|
||||||
}
|
}
|
||||||
return workflow && workflow.get('type').get();
|
return workflow && workflow.get('type').get();
|
||||||
}
|
}
|
||||||
|
|
||||||
var directSpecificData = {
|
var directSpecificData = {
|
||||||
'on-complete': {
|
'on-complete': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@required': false
|
'@required': false
|
||||||
},
|
},
|
||||||
'on-success': {
|
'on-success': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@required': false
|
'@required': false
|
||||||
},
|
},
|
||||||
'on-error': {
|
'on-error': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@required': false
|
'@required': false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reverseSpecificData = {
|
reverseSpecificData = {
|
||||||
'requires': {
|
'requires': {
|
||||||
'@type': Array,
|
'@type': Array,
|
||||||
'*': {
|
'*': {
|
||||||
'@class': Barricade.Primitive.extend({
|
'@class': Barricade.Primitive.extend({
|
||||||
'name': 'Action'
|
'name': 'Action'
|
||||||
}, {
|
}, {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@enum': function() {
|
'@enum': function() {
|
||||||
var container = this._container,
|
var container = this._container,
|
||||||
workflow, task;
|
workflow, task;
|
||||||
while ( container ) {
|
while ( container ) {
|
||||||
if ( container.instanceof(types.Mistral.Task) ) {
|
if ( container.instanceof(types.Mistral.Task) ) {
|
||||||
task = container;
|
task = container;
|
||||||
}
|
}
|
||||||
if ( container.instanceof(types.Mistral.Workflow) ) {
|
if ( container.instanceof(types.Mistral.Workflow) ) {
|
||||||
workflow = container;
|
workflow = container;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
container = container._container;
|
container = container._container;
|
||||||
}
|
}
|
||||||
if ( workflow && task ) {
|
if ( workflow && task ) {
|
||||||
return workflow.get('tasks').toArray().filter(function(taskItem) {
|
return workflow.get('tasks').toArray().filter(function(taskItem) {
|
||||||
return !(taskItem === task) && taskItem.get('name').get();
|
return !(taskItem === task) && taskItem.get('name').get();
|
||||||
}).map(function(taskItem) {
|
}).map(function(taskItem) {
|
||||||
return taskItem.get('name').get();
|
return taskItem.get('name').get();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
types.base.AcceptsMixin.call(self, [
|
types.base.AcceptsMixin.call(self, [
|
||||||
{
|
{
|
||||||
label: 'Action-based',
|
label: 'Action-based',
|
||||||
value: function() {
|
value: function() {
|
||||||
var workflowType = getParentWorkflowType();
|
var workflowType = getParentWorkflowType();
|
||||||
if ( workflowType === 'direct' ) {
|
if ( workflowType === 'direct' ) {
|
||||||
return types.Mistral.ActionTask.extend({}, directSpecificData);
|
return types.Mistral.ActionTask.extend({}, directSpecificData);
|
||||||
} else if ( workflowType === 'reverse' ) {
|
} else if ( workflowType === 'reverse' ) {
|
||||||
return types.Mistral.ActionTask.extend({}, reverseSpecificData);
|
return types.Mistral.ActionTask.extend({}, reverseSpecificData);
|
||||||
} else {
|
} else {
|
||||||
return types.Mistral.ActionTask;
|
return types.Mistral.ActionTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
label: 'Workflow-based',
|
label: 'Workflow-based',
|
||||||
value: function() {
|
value: function() {
|
||||||
var workflowType = getParentWorkflowType();
|
var workflowType = getParentWorkflowType();
|
||||||
if ( workflowType === 'direct' ) {
|
if ( workflowType === 'direct' ) {
|
||||||
return types.Mistral.WorkflowTask.extend({}, directSpecificData);
|
return types.Mistral.WorkflowTask.extend({}, directSpecificData);
|
||||||
} else if ( workflowType === 'reverse' ) {
|
} else if ( workflowType === 'reverse' ) {
|
||||||
return types.Mistral.WorkflowTask.extend({}, reverseSpecificData);
|
return types.Mistral.WorkflowTask.extend({}, reverseSpecificData);
|
||||||
} else {
|
} else {
|
||||||
return types.Mistral.WorkflowTask;
|
return types.Mistral.WorkflowTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
'@type': Object,
|
'@type': Object,
|
||||||
'?': {'@class': types.Mistral.Task}
|
'?': {'@class': types.Mistral.Task}
|
||||||
});
|
});
|
||||||
|
|
||||||
types.Mistral.WorkflowTask = types.Mistral.Task.extend({},
|
types.Mistral.WorkflowTask = types.Mistral.Task.extend({},
|
||||||
{
|
{
|
||||||
'workflow': {
|
'workflow': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@enum': function() {
|
'@enum': function() {
|
||||||
var workflows = workbook.get('workflows').toArray();
|
var workflows = workbook.get('workflows').toArray();
|
||||||
return workflows.map(function(workflowItem) {
|
return workflows.map(function(workflowItem) {
|
||||||
return workflowItem.get('name').get();
|
return workflowItem.get('name').get();
|
||||||
}).filter(function (name) {
|
}).filter(function (name) {
|
||||||
return name;
|
return name;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
types.Mistral.ActionTask = types.Mistral.Task.extend({},
|
types.Mistral.ActionTask = types.Mistral.Task.extend({},
|
||||||
{
|
{
|
||||||
'action': {
|
'action': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@enum': function() {
|
'@enum': function() {
|
||||||
var predefinedActions = types.getOpenStackActions(),
|
var predefinedActions = types.getOpenStackActions(),
|
||||||
actions = workbook.get('actions').toArray();
|
actions = workbook.get('actions').toArray();
|
||||||
return predefinedActions.concat(actions.map(function(actionItem) {
|
return predefinedActions.concat(actions.map(function(actionItem) {
|
||||||
return actionItem.get('name').get();
|
return actionItem.get('name').get();
|
||||||
}).filter(function(name) {
|
}).filter(function(name) {
|
||||||
return name; }
|
return name; }
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
types.Mistral.Workflow = Barricade.create({
|
types.Mistral.Workflow = Barricade.create({
|
||||||
'@type': Object,
|
'@type': Object,
|
||||||
|
'@meta': {'groups': 'panel3'},
|
||||||
|
|
||||||
'name': {'@type': String},
|
'name': {'@type': String},
|
||||||
'type': {
|
'type': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@enum': ['reverse', 'direct'],
|
'@enum': ['reverse', 'direct'],
|
||||||
'@default': 'direct'
|
'@default': 'direct'
|
||||||
},
|
},
|
||||||
'input': {
|
'input': {
|
||||||
'@type': Array,
|
'@type': Array,
|
||||||
'@required': false,
|
'@required': false,
|
||||||
'*': {
|
'*': {
|
||||||
'@class': Barricade.Primitive.extend({
|
'@class': Barricade.Primitive.extend({
|
||||||
'name': 'Primitive'
|
'name': 'Primitive'
|
||||||
}, {
|
}, {
|
||||||
'@type': String
|
'@type': String
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'output': {
|
'output': {
|
||||||
'@type': String,
|
'@type': String,
|
||||||
'@required': false
|
'@required': false
|
||||||
},
|
},
|
||||||
'task-defaults': {
|
'task-defaults': {
|
||||||
'@type': Object,
|
'@type': Object,
|
||||||
'@required': false,
|
'@required': false,
|
||||||
'on-error': {'@type': String},
|
'on-error': {'@type': String},
|
||||||
'on-success': {'@type': String},
|
'on-success': {'@type': String},
|
||||||
'on-complete': {'@type': String},
|
'on-complete': {'@type': String},
|
||||||
'policies': {'@class': types.Mistral.Policy}
|
'policies': {'@class': types.Mistral.Policy}
|
||||||
},
|
},
|
||||||
'tasks': {
|
'tasks': {
|
||||||
'@class': types.Mistral.Tasks
|
'@class': types.Mistral.Tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
types.Mistral.Workbook = Barricade.create({
|
types.Mistral.Workbook = Barricade.create({
|
||||||
'@type': Object,
|
'@type': Object,
|
||||||
|
|
||||||
'version': {
|
'version': {
|
||||||
'@type': Number,
|
'@type': Number,
|
||||||
'@default': 2
|
'@meta': {'groups': ['panel1']},
|
||||||
},
|
'@default': 2
|
||||||
'name': {
|
},
|
||||||
'@type': String
|
'name': {
|
||||||
},
|
'@type': String,
|
||||||
'description': {
|
'@meta': {'groups': ['panel1']}
|
||||||
'@type': String,
|
},
|
||||||
'@required': false
|
'description': {
|
||||||
},
|
'@type': String,
|
||||||
'actions': {
|
'@meta': {'groups': ['panel1']},
|
||||||
'@type': Object,
|
'@required': false
|
||||||
'@required': false,
|
},
|
||||||
'?': {
|
'actions': {
|
||||||
'@class': types.Mistral.Action
|
'@type': Object,
|
||||||
}
|
'@required': false,
|
||||||
},
|
'?': {
|
||||||
'workflows': {
|
'@class': types.Mistral.Action
|
||||||
'@type': Object,
|
}
|
||||||
'?': {
|
},
|
||||||
'@class': types.Mistral.Workflow
|
'workflows': {
|
||||||
}
|
'@type': Object,
|
||||||
}
|
'?': {
|
||||||
});
|
'@class': types.Mistral.Workflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
.run(function($http, $templateCache) {
|
.run(function($http, $templateCache) {
|
||||||
var fields = ['dictionary', 'frozendict', 'list', 'string', 'varlist'];
|
var fields = ['dictionary', 'frozendict', 'list', 'string',
|
||||||
|
'varlist', 'text', 'group', 'yaqllist'];
|
||||||
fields.forEach(function(field) {
|
fields.forEach(function(field) {
|
||||||
var base = '/static/mistral/js/angular-templates/fields/';
|
var base = '/static/mistral/js/angular-templates/fields/';
|
||||||
$http.get(base + field + '.html').success(function(templateContent) {
|
$http.get(base + field + '.html').success(function(templateContent) {
|
||||||
|
@ -25,4 +26,42 @@
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
.filter('prepareSchema', function($filter) {
|
||||||
|
var toArray = $filter('toArray'),
|
||||||
|
orderBy = $filter('orderBy');
|
||||||
|
function schemaToArray(schema) {
|
||||||
|
return angular.isArray(schema) ? schema : orderBy(
|
||||||
|
toArray(schema, true), 'index').map(function(item) {
|
||||||
|
item.name = item.$key;
|
||||||
|
if ( item.type === 'panel' ) {
|
||||||
|
item.panelIndex = item.index;
|
||||||
|
}
|
||||||
|
if ( item.type === 'panel' || item.type === 'group' ) {
|
||||||
|
item.value = schemaToArray(item.value);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return schemaToArray;
|
||||||
|
})
|
||||||
|
|
||||||
|
.filter('normalizePanels', function() {
|
||||||
|
return function(collection) {
|
||||||
|
return collection.map(function(panelSpec) {
|
||||||
|
if ( panelSpec[0].type === 'panel' ) {
|
||||||
|
var data = panelSpec[0];
|
||||||
|
panelSpec.length = data.value.length;
|
||||||
|
for ( var i = 0; i < panelSpec.length; i++ ) {
|
||||||
|
panelSpec[i] = data.value[i];
|
||||||
|
}
|
||||||
|
panelSpec.multiple = data.multiple;
|
||||||
|
panelSpec.name = data.name;
|
||||||
|
}
|
||||||
|
return panelSpec;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})();
|
})();
|
|
@ -51,40 +51,34 @@
|
||||||
<!-- Data panel start -->
|
<!-- Data panel start -->
|
||||||
<div class="two-panels">
|
<div class="two-panels">
|
||||||
<div class="left-panel">
|
<div class="left-panel">
|
||||||
<!-- root-level parameters -->
|
<div ng-repeat="panelSpec in schema | prepareSchema | groupBy: 'panelIndex' | toArray:true | orderBy: '$key' | normalizePanels track by panelSpec.$key">
|
||||||
<div class="panel panel-default merlin-panel" id="panel0">
|
<panel ng-if="panelSpec.multiple" ng-repeat="item in data[panelSpec.name] track by item.id" title="{$ item.name $}" on-remove="remove('{$ panelSpec.name $}', item)">
|
||||||
<div class="panel-body">
|
<div ng-repeat="specs in panelSpec | groupBy: 'row' | toArray: true | orderBy: '$key' track by specs.$key">
|
||||||
<div class="two-columns">
|
<div ng-class="{'three-columns': specs[0].row !== undefined }">
|
||||||
<div class="left-column">
|
<div ng-repeat="spec in specs track by spec.name"
|
||||||
<div class="form-group">
|
ng-class="{'right-column': $even && isAtomic(spec.type), 'left-column': $odd && isAtomic(spec.type)}">
|
||||||
<label for="workbookName">Name</label>
|
<typed-field></typed-field>
|
||||||
<input type="text" class="form-control" id="workbookName" placeholder="Workbook1">
|
<div class="clearfix" ng-show="$even"></div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="right-column">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="workbookDesc">Description</label>
|
|
||||||
<textarea class="form-control" id="workbookDesc" placeholder="Type a description here"></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</panel>
|
||||||
|
<panel ng-if="!panelSpec.multiple">
|
||||||
|
<!-- ugly duplication here -->
|
||||||
|
<div ng-repeat="specs in panelSpec | groupBy: 'row' | toArray: true | orderBy: '$key' track by specs.$key">
|
||||||
|
<div ng-class="{'two-columns': specs[0].row !== undefined }">
|
||||||
|
<div ng-repeat="spec in specs track by spec.name"
|
||||||
|
ng-class="{'right-column': $even && isAtomic(spec.type), 'left-column': $odd && isAtomic(spec.type)}">
|
||||||
|
<typed-field></typed-field>
|
||||||
|
<div class="clearfix" ng-show="$even"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</panel>
|
||||||
</div>
|
</div>
|
||||||
<!-- Action added -->
|
|
||||||
<collapsible-panel ng-controller="actionCtrl" ng-repeat="item in data.actions track by item.id" title="{$ item.name $}" removable="remove('actions', item)">
|
|
||||||
<div ng-repeat="specs in schema.action | groupBy: 'group' | toArray:true | orderBy: '-$key' track by specs.$key">
|
|
||||||
<div ng-class="{'three-columns': specs[0].group}">
|
|
||||||
<div ng-repeat="spec in specs track by spec.name"
|
|
||||||
ng-class="{'right-column': $even && isAtomic(spec.type), 'left-column': $odd && isAtomic(spec.type)}">
|
|
||||||
<typed-field></typed-field>
|
|
||||||
<div class="clearfix" ng-show="$even"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</collapsible-panel>
|
|
||||||
<!-- panel with workflow -->
|
<!-- panel with workflow -->
|
||||||
<div ng-controller="workflowsCtrl">
|
<div ng-controller="workflowsCtrl">
|
||||||
<collapsible-panel title="Workflow1" removable="true">
|
<panel title="Workflow1" removable="true">
|
||||||
<!-- 2 simple inputs in a single row -->
|
<!-- 2 simple inputs in a single row -->
|
||||||
<div class="three-columns">
|
<div class="three-columns">
|
||||||
<div class="left-column">
|
<div class="left-column">
|
||||||
|
@ -267,7 +261,7 @@
|
||||||
</collapsible-group>
|
</collapsible-group>
|
||||||
</collapsible-group>
|
</collapsible-group>
|
||||||
</collapsible-group>
|
</collapsible-group>
|
||||||
</collapsible-panel>
|
</panel>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- YAML Panel -->
|
<!-- YAML Panel -->
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue