Add parameters configuration UI for entities
Signed-off-by: Andrew Donald Kennedy <andrew.kennedy@cloudsoftcorp.com>
diff --git a/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js b/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
index 38604a3..ecfefae 100644
--- a/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
+++ b/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
@@ -68,6 +68,7 @@
populateEntityFromApi: populateEntityFromApiSuccess,
populateLocationFromApi: populateLocationFromApiSuccess,
addConfigKeyDefinition: addConfigKeyDefinition,
+ addParameterDefinition: addParameterDefinition,
getRelationships: getRelationships,
};
@@ -516,13 +517,23 @@
function addConfigKeyDefinition(config, key) {
config.push({
- "constraints": [],
- "description": "",
"name": key,
"label": key,
+ "description": "",
"priority": 1,
"pinned": true,
"type": "java.lang.String",
+ "constraints": [],
+ });
+ }
+
+ function addParameterDefinition(params, key) {
+ params.push({
+ "name": key,
+ "description": "",
+ "type": "string",
+ "default": "",
+ "constraints": [],
});
}
diff --git a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.directive.js b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.directive.js
index 53be4f2..7083173 100644
--- a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.directive.js
+++ b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.directive.js
@@ -82,28 +82,46 @@
model: '='
},
controller: ['$scope', '$element', controller],
- templateUrl: function (tElement, tAttrs) {
- return tAttrs.templateUrl || TEMPLATE_URL;
+ templateUrl: function (tElement, tAttrs) {
+ return tAttrs.templateUrl || TEMPLATE_URL;
},
link: link,
controllerAs: 'specEditor',
};
function controller($scope, $element) {
- (composerOverrides.configureSpecEditorController || function() {})(this, $scope, $element);
-
+ (composerOverrides.configureSpecEditorController || function () {
+ })(this, $scope, $element);
+
// does very little currently, but link adds to this
return this;
}
function link(scope, element, attrs, specEditor) {
scope.specEditor = specEditor;
+ scope.getParameter = getParameter;
+ scope.addParameter = addParameter;
scope.addConfigKey = addConfigKey;
scope.FAMILIES = EntityFamily;
scope.RESERVED_KEYS = RESERVED_KEYS;
scope.REPLACED_DSL_ENTITYSPEC = REPLACED_DSL_ENTITYSPEC;
+ scope.parameters = [];
+ scope.config = {};
let defaultState = {
+ parameters: {
+ add: {
+ value: '',
+ open: false
+ },
+ search: '',
+ focus: '',
+ filter: {
+ open: false,
+ },
+ open: false,
+
+ },
config: {
add: {
value: '',
@@ -112,7 +130,7 @@
search: '',
focus: '',
filter: {
- values: { suggested: true, required: true, inuse: true },
+ values: {suggested: true, required: true, inuse: true},
open: false,
},
// TODO would be nice to set null here, then have it go true if there is filtered config
@@ -137,15 +155,17 @@
open: false
}
};
+
// allow downstream to configure this controller and/or scope
- (composerOverrides.configureSpecEditor || function() {})(specEditor, scope, element, $state, $compile, $templateCache);
+ (composerOverrides.configureSpecEditor || function () {
+ })(specEditor, scope, element, $state, $compile, $templateCache);
scope.filters = {
- config: CONFIG_FILTERS
+ config: CONFIG_FILTERS,
};
- scope.isFilterDisabled = (filter) => filter.id!='all' && scope.state.config.filter.values['all'];
+ scope.isFilterDisabled = (filter) => filter.id !== 'all' && scope.state.config.filter.values['all'];
scope.onFilterClicked = (filter) => {
- if (!scope.isFilterDisabled(filter)) scope.state.config.filter.values[ filter.id ] = !scope.state.config.filter.values[ filter.id ];
+ if (!scope.isFilterDisabled(filter)) scope.state.config.filter.values[filter.id] = !scope.state.config.filter.values[filter.id];
};
scope.state = sessionStorage && sessionStorage.getItem(scope.model._id)
@@ -160,25 +180,31 @@
}
}
}, true);
- scope.$watch('state.config.filter.values', ()=> {
+ scope.$watch('state.config.filter.values', () => {
scope.state.config.add.list = getAddListConfig();
});
loadCustomConfigWidgetMetadata(scope);
- scope.config = {};
- scope.$watch('model', (newVal, oldVal)=> {
+ // Model
+ scope.$watch('model', (newVal, oldVal) => {
if (newVal && !newVal.equals(oldVal)) {
loadLocalConfigFromModel();
+ loadLocalParametersFromModel();
}
}, true);
-
- scope.$watch('model.id', ()=> {
+ scope.$watch('model.id', () => {
blueprintService.refreshAllRelationships();
});
+ // Parameters
+ scope.$watch('parameters', (newVal, oldVal) => {
+ setModelFromLocalParameters();
+ scope.model.clearIssues({group: 'parameters'});
+ }, true);
+
// Config
- scope.$watch('config', (newVal, oldVal)=> {
+ scope.$watch('config', (newVal, oldVal) => {
setModelFromLocalConfig();
scope.model.clearIssues({group: 'config'});
blueprintService.refreshRelationships(scope.model).then(() => {
@@ -188,12 +214,13 @@
});
}, true);
- scope.getObjectSize = (object)=> {
- return specEditor.defined(object) && object!=null ? Object.keys(object).length : 0;
+ scope.getObjectSize = (object) => {
+ return specEditor.defined(object) && object != null ? Object.keys(object).length : 0;
};
+
function findNext(element, clazz, stopClazz) {
let el = element, last = null;
- while (last!=el) {
+ while (last !== el) {
last = el;
if (el.children().length) {
el = angular.element(el.children()[0]);
@@ -210,13 +237,14 @@
}
return null;
}
+
function findPrev(element, clazz, stopClazz) {
let el = element, last = null;
- while (last!=el) {
+ while (last !== el) {
last = el;
if (el.children().length) {
// this still does children first, not ideal but okay for how we use it
- el = angular.element(el.children()[el.children().length-1]);
+ el = angular.element(el.children()[el.children().length - 1]);
} else {
while (el.length && !el[0].previousElementSibling) {
el = el.parent();
@@ -230,9 +258,10 @@
}
return null;
}
+
function findAncestor(element, clazz, stopClazz) {
let el = element, last = null;
- while (last!=el) {
+ while (last !== el) {
last = el;
el = el.parent();
if (el.hasClass(clazz)) {
@@ -242,6 +271,7 @@
}
return null;
}
+
function focusIfPossible(event, next) {
if (next && next.length) {
if (event) event.preventDefault();
@@ -252,6 +282,7 @@
return false;
}
}
+
scope.nonempty = (o) => o && Object.keys(o).length;
scope.defined = specEditor.defined = (o) => (typeof o !== 'undefined');
specEditor.advanceOutToFormGroupInPanel = (element, event) => {
@@ -259,10 +290,10 @@
};
specEditor.advanceControlInFormGroup = (element, event) => {
focusIfPossible(event, findNext(element, "form-control", "form-group")) ||
- specEditor.advanceOutToFormGroupInPanel(element, event);
+ specEditor.advanceOutToFormGroupInPanel(element, event);
};
- scope.onAddMapProperty = (configKey, key, ev)=> {
+ scope.onAddMapProperty = (configKey, key, ev) => {
if (key) {
if (!scope.config[configKey]) {
scope.config[configKey] = {};
@@ -275,7 +306,7 @@
let element = angular.element(ev.target);
let prev = findPrev(element, "form-control", "form-group");
focusIfPossible(null, prev) ||
- specEditor.advanceOutToFormGroupInPanel(element, null);
+ specEditor.advanceOutToFormGroupInPanel(element, null);
}, 0);
} else {
// user entered a key that already exists;
@@ -284,16 +315,16 @@
}
};
scope.cycleExpandMode = specEditor.cycleExpandMode = function (expandMode, ctx, item, focus) {
- return expandMode == 'default' ? 'open' :
- expandMode == 'open' ? 'closed' :
- 'default';
- }
+ return expandMode === 'default' ? 'open' :
+ expandMode === 'open' ? 'closed' :
+ 'default';
+ };
scope.onDeleteMapProperty = specEditor.onDeleteMapProperty = function (model, key) {
if (model && model.hasOwnProperty(key)) {
delete model[key];
}
};
- scope.onAddListItem = specEditor.onAddListItem = (configKey, item, ev)=> {
+ scope.onAddListItem = specEditor.onAddListItem = (configKey, item, ev) => {
if (item) {
if (!scope.config[configKey]) {
scope.config[configKey] = [];
@@ -309,14 +340,14 @@
model.splice(index, 1);
}
};
- scope.isConfigHidden = specEditor.isConfigHidden = (config)=> {
+ scope.isConfigHidden = specEditor.isConfigHidden = (config) => {
let allConfig = scope.model.miscData.get('config');
if (allConfig.indexOf(config) === -1) {
return false;
}
return $filter('specEditorConfig')(allConfig, scope.state.config.filter.values).indexOf(config) === -1;
};
- scope.onFocusOnConfig = specEditor.onFocusOnConfig = ($item)=> {
+ scope.onFocusOnConfig = specEditor.onFocusOnConfig = ($item) => {
scope.state.config.search = '';
scope.state.config.add.value = '';
scope.state.config.add.open = false;
@@ -325,14 +356,23 @@
scope.state.config.filter.values.all = true;
}
};
- scope.recordFocus = specEditor.recordFocus = ($item) => {
+ scope.onFocusOnParameter = specEditor.onFocusOnParameter = ($item) => {
+ scope.state.parameters.search = '';
+ scope.state.parameters.add.value = '';
+ scope.state.parameters.add.open = false;
+ scope.state.parameters.focus = $item.name;
+ };
+ scope.recordConfigFocus = specEditor.recordConfigFocus = ($item) => {
scope.state.config.focus = $item.name;
};
+ scope.recordParameterFocus = specEditor.recordParameterFocus = ($item) => {
+ scope.state.parameters.focus = $item.name;
+ };
- scope.removeAdjunct = ($event, adjunct)=> {
+ scope.removeAdjunct = ($event, adjunct) => {
$event.preventDefault();
$event.stopPropagation();
- switch(adjunct.family) {
+ switch (adjunct.family) {
case EntityFamily.POLICY:
scope.model.removePolicy(adjunct._id);
break;
@@ -342,7 +382,7 @@
}
};
- scope.removeModel = ()=> {
+ scope.removeModel = () => {
switch (scope.model.family) {
case EntityFamily.ENRICHER:
scope.model.parent.removeEnricher(scope.model._id);
@@ -357,25 +397,30 @@
$state.go(graphicalState.name);
};
- scope.getConfigIssues = specEditor.getConfigIssues = ()=> {
+ scope.getParameterIssues = specEditor.getParameterIssues = () => {
return scope.model.issues
- .filter((issue)=>(issue.group === 'config'))
+ .filter((issue) => (issue.group === 'parameters'))
.concat(Object.values(scope.model.getClusterMemberspecEntities())
- .filter((spec)=>(spec && spec.hasIssues()))
- .reduce((acc, spec)=>(acc.concat(spec.issues)), []));
+ .filter((spec) => (spec && spec.hasIssues()))
+ .reduce((acc, spec) => (acc.concat(spec.issues)), []));
};
-
- scope.getPoliciesIssues = ()=> {
- return scope.model.getPoliciesAsArray().reduce((acc, policy)=> {
+ scope.getConfigIssues = specEditor.getConfigIssues = () => {
+ return scope.model.issues
+ .filter((issue) => (issue.group === 'config'))
+ .concat(Object.values(scope.model.getClusterMemberspecEntities())
+ .filter((spec) => (spec && spec.hasIssues()))
+ .reduce((acc, spec) => (acc.concat(spec.issues)), []));
+ };
+ scope.getPoliciesIssues = () => {
+ return scope.model.getPoliciesAsArray().reduce((acc, policy) => {
if (policy.hasIssues()) {
acc = acc.concat(policy.issues)
}
return acc;
}, []);
};
-
- scope.getEnrichersIssues = ()=> {
- return scope.model.getEnrichersAsArray().reduce((acc, enricher)=> {
+ scope.getEnrichersIssues = () => {
+ return scope.model.getEnrichersAsArray().reduce((acc, enricher) => {
if (enricher.hasIssues()) {
acc = acc.concat(enricher.issues)
}
@@ -393,7 +438,7 @@
out.push('<div class="paragraph-spacing"></div>');
out.push($sanitize(item));
}
- out.splice(0,1);
+ out.splice(0, 1);
return $sce.trustAsHtml(out.join("\n"));
};
@@ -426,20 +471,20 @@
// override to use string editor if the editor doesn't support the value
// (probably this is an error, though type-coercion might make it not so)
if (type === 'boolean') {
- if (typeof val !== type) return type+'-manual'; // causes default string editor
+ if (typeof val !== type) return type + '-manual'; // causes default string editor
} else if (type === 'map') {
- if (typeof val !== 'object') return type+'-manual'; // causes default string editor
+ if (typeof val !== 'object') return type + '-manual'; // causes default string editor
} else if (type === 'array') {
- if (!Array.isArray(val)) return type+'-manual'; // causes default string editor
+ if (!Array.isArray(val)) return type + '-manual'; // causes default string editor
}
}
if (scope.state.config.codeModeActive[item.name]) {
// code mode forces manual editor
- return type+'-manual';
+ return type + '-manual';
}
return type;
- };
+ }
scope.getConfigWidgetMode = (item, value) => {
// record the value as `item.widgetMode` so we can reference it subsequently, as well as returning it
@@ -449,13 +494,25 @@
// if type isn't set then infer
if (value instanceof Array) {
- definition.widgetMode = 'array';
+ item.widgetMode = 'array';
} else if (value instanceof Object) {
- definition.widgetMode = 'map';
+ item.widgetMode = 'map';
} else {
- definition.widgetMode = 'unknown';
+ item.widgetMode = 'unknown';
}
- }
+ return item.widgetMode;
+ };
+ scope.getParameterWidgetMode = (item) => {
+ let type = item.type || item.typeName;
+
+ if (type === 'java.lang.Boolean') type = 'boolean';
+ else if (type === 'java.util.Map') type = 'map';
+ else if (type === 'java.util.Set' || type === 'java.util.List' || type === 'java.util.Collection' || type.startsWith('List<')) type = 'array';
+
+ if (type.startsWith('AWS::')) type = 'unknown';
+
+ return type;
+ };
scope.isCodeModeAvailable = (item) => {
let val = scope.config[item.name];
@@ -491,7 +548,7 @@
if (val instanceof Array || val instanceof Object) return true;
// other primitive
return false;
- }
+ };
scope.codeModeClick = (item) => {
if (scope.state.config.codeModeForced[item.name] && scope.state.config.codeModeActive[item.name]) {
// if forced and active, don't allow clicks
@@ -503,7 +560,7 @@
if (!specEditor.defined(value)) {
value = null;
}
- if (value!=null) {
+ if (value != null) {
if (oldMode) {
// leaving code mode
try {
@@ -548,43 +605,43 @@
value = JSON.stringify(value);
}
}
- if (value!=null) {
+ if (value != null) {
scope.config[item.name] = value;
}
}
scope.state.config.codeModeActive[item.name] = !oldMode;
- if (value!=null) {
+ if (value != null) {
// local config changed, make sure model is updated too
setModelFromLocalConfig();
}
};
scope.getJsonModeTitle = (itemName) => {
if (!scope.state.config.codeModeActive[itemName]) {
- return "Treat this value as a JSON-encoded object ["+itemName+"]";
+ return "Treat this value as a JSON-encoded object [" + itemName + "]";
}
if (scope.state.config.codeModeForced[itemName]) {
- return "This data is a complex object and can only be entered as JSON ["+itemName+"]";
+ return "This data is a complex object and can only be entered as JSON [" + itemName + "]";
} else {
- return "Edit in simple mode, unwrapping JSON if possible ["+itemName+"]";
+ return "Edit in simple mode, unwrapping JSON if possible [" + itemName + "]";
}
};
/** returns 'enabled' or 'disabled' if a widget is defined, or null if no special widget is defined */
specEditor.getCustomConfigWidgetMode = (item) => {
- var widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
+ let widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
if (!widgetMetadata || widgetMetadata["error"]) return null;
return widgetMetadata["enabled"] ? 'enabled' : 'disabled';
};
specEditor.toggleCustomConfigWidgetMode = (item, newval) => {
- var widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
+ let widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
if (!widgetMetadata) {
- $log.error('Custom widget mode should not be toggled when not available: '+item.name);
+ $log.error('Custom widget mode should not be toggled when not available: ' + item.name);
return null;
}
if (!specEditor.defined(newval)) newval = !widgetMetadata.enabled;
widgetMetadata.enabled = newval;
- }
+ };
specEditor.getCustomConfigWidgetModeTitle = (item) => {
- var widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
+ let widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
if (!widgetMetadata) {
// shouldn't be visible
return "(custom widget not available)";
@@ -592,18 +649,20 @@
return widgetMetadata.enabled ? "Use standard widget" : "Use custom widget";
};
specEditor.getCustomConfigWidgetTemplate = (item) => {
- var widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
- var widgetName = $sanitize(widgetMetadata.widget || '--no-widget--');
- var templateName = 'custom-config-widget-'+widgetName;
+ let widgetMetadata = scope.state.config.customConfigWidgetMetadata[item.name];
+ let widgetName = $sanitize(widgetMetadata.widget || '--no-widget--');
+ let templateName = 'custom-config-widget-' + widgetName;
if (!$templateCache.get(templateName)) {
- var widgetDirective = widgetName.replace(/(-[a-z])/g, function($1){return $1[1].toUpperCase();})+'Directive';
+ let widgetDirective = widgetName.replace(/(-[a-z])/g, function ($1) {
+ return $1[1].toUpperCase();
+ }) + 'Directive';
if ($injector.has(widgetDirective)) {
- $templateCache.put(templateName, '<'+widgetName+' item="item" params="state.config.customConfigWidgetMetadata[item.name]" config="config" model="model"/>');
+ $templateCache.put(templateName, '<' + widgetName + ' item="item" params="state.config.customConfigWidgetMetadata[item.name]" config="config" model="model"/>');
} else {
- $log.error('Missing directive '+widgetDirective+' for custom widget for '+item.name+'; falling back to default widget');
+ $log.error('Missing directive ' + widgetDirective + ' for custom widget for ' + item.name + '; falling back to default widget');
scope.state.config.customConfigWidgetMetadata[item.name].error = "Missing directive";
templateName = "error-" + templateName;
- $templateCache.put(templateName, '<i>Widget '+widgetName+' missing</i>');
+ $templateCache.put(templateName, '<i>Widget ' + widgetName + ' missing</i>');
}
}
return templateName;
@@ -611,7 +670,7 @@
specEditor.isDsl = (key, index) => {
let val = scope.model.config.get(key);
- if (specEditor.defined(val) && specEditor.defined(index) && index!=null) val = val[index];
+ if (specEditor.defined(val) && specEditor.defined(index) && index != null) val = val[index];
return specEditor.isDslVal(val);
};
specEditor.isDslVal = (val) => {
@@ -620,9 +679,9 @@
};
specEditor.isDslWizardButtonAllowed = (key, index, nonModelValue) => {
let val = scope.model.config.get(key);
- if (specEditor.defined(val) && specEditor.defined(index) && index!=null) val = val[index];
- if (!specEditor.defined(val) || val===null || val==='') val = nonModelValue;
- if (!specEditor.defined(val) || val===null || val==='') return true;
+ if (specEditor.defined(val) && specEditor.defined(index) && index != null) val = val[index];
+ if (!specEditor.defined(val) || val === null || val === '') val = nonModelValue;
+ if (!specEditor.defined(val) || val === null || val === '') return true;
if (specEditor.isDslVal(val)) {
return true;
}
@@ -635,39 +694,47 @@
return [];
}
let filteredConfig = $filter('specEditorConfig')(scope.model.miscData.get('config'), scope.state.config.filter.values, scope.model);
- return scope.model.miscData.get('config').map((config)=> {
+ return scope.model.miscData.get('config').map((config) => {
config.isHidden = scope.model.miscData.get('config').indexOf(config) > -1 ? filteredConfig.indexOf(config) === -1 : false;
return config;
});
}
function loadCustomConfigWidgetMetadata(model) {
- var customConfigWidgets = (scope.model.miscData.get('ui-composer-hints') || {})['config-widgets'] || [];
- customConfigWidgets.forEach( (wd) => {
- var keys = wd.keys || [ wd.key ];
- keys.forEach( (k) => {
- scope.state.config.customConfigWidgetMetadata[k] = angular.extend({ enabled: true }, scope.state.config.customConfigWidgetMetadata[k], wd);
+ let customConfigWidgets = (scope.model.miscData.get('ui-composer-hints') || {})['config-widgets'] || [];
+ customConfigWidgets.forEach((wd) => {
+ let keys = wd.keys || [wd.key];
+ keys.forEach((k) => {
+ scope.state.config.customConfigWidgetMetadata[k] = angular.extend({enabled: true}, scope.state.config.customConfigWidgetMetadata[k], wd);
});
});
}
- /* config state for each item is stored in multiple places:
- * * scope.config = map of values used/set by editor (strings, map of strings, json code if using code mode, etc);
- * this should be suitable for ng-model to work with, so e.g. if using code mode we need to put JSON.stringify value in here,
- * and note any change here immediately (on next digest) updates scope.model.config, which e.g. in code mode
- * will JSON.parse
- * * scope.model.config = map of values used in internal model
- * * scope.model.miscData.get('config') = list of config keys with their metadata, including derived widgetMode
- * * scope.state.config.{codeModeActive,dslManualOverride} = maps of booleans where edit modes are set and remembered for configs
+ /**
+ * The configuration data for each item is stored in multiple places:
+ *
+ * scope.config
+ * A map of values used/set by editor, which can be strings, a map of strings, the JSON representation of the
+ * object if using code mode, etc. This should be suitable for ng-model to work with, so e.g. if using code
+ * mode we need to put JSON.stringify value in here, and note any change here immediately (on next digest)
+ * updates scope.model.config, which e.g. in code mode will JSON.parse
+ *
+ * scope.model.config
+ * A map of values used in internal model
+ *
+ * scope.model.miscData.get('config')
+ * A list of config keys with their metadata, including derived widgetMode
+ *
+ * scope.state.config.{codeModeActive,dslManualOverride}
+ * Maps of booleans where edit modes are set and remembered for configs
*/
function loadLocalConfigFromModel() {
- let map = scope.model.config;
+ let modelConfig = scope.model.config;
let result = {};
- for (let [key, value] of map) {
+ for (let [key, value] of modelConfig) {
if (blueprintService.isReservedKey(key)) {
- // skip
- continue;
+ continue; // skip
}
result[key] = getLocalConfigValueFromModelValue(key, value);
@@ -676,7 +743,7 @@
}
function getLocalConfigValueFromModelValue(key, value) {
- if (!specEditor.defined(value) || value==null) {
+ if (!specEditor.defined(value) || value == null) {
return value;
}
@@ -691,7 +758,6 @@
let definition = scope.model.miscData.get('config').find(config => config.name === key);
if (!definition) {
- // odd, no def'n for this key
definition = {};
scope.getConfigWidgetMode(definition, value)
} else {
@@ -711,7 +777,7 @@
// also supporting yaml and comments, but that is a bigger task!)
if (scope.config && typeof scope.config[key] === 'string') {
try {
- if (JSON.stringify(JSON.parse(scope.config[key]))===JSON.stringify(value)) {
+ if (JSON.stringify(JSON.parse(scope.config[key])) === JSON.stringify(value)) {
return scope.config[key];
}
} catch (ignoredError) {
@@ -731,7 +797,7 @@
return value.map(item => {
if (item instanceof Dsl) {
return item.toString();
- } else if (item instanceof Array || item instanceof Object) {
+ } else if (item instanceof Array || item instanceof Object) {
throw 'not simple json in array';
} else {
return item;
@@ -740,7 +806,7 @@
} else if (definition.widgetMode === 'map') {
let object = {};
for (let keyObject in value) {
- if (value[keyObject] instanceof Dsl) {
+ if (value[keyObject] instanceof Dsl) {
object[keyObject] = value[keyObject].toString();
} else if (value[keyObject] instanceof Array || value[keyObject] instanceof Object) {
throw 'not simple json in map';
@@ -769,11 +835,11 @@
}
// all other primitives treat as string (as they will get a string-based widget)
- return ""+value;
+ return "" + value;
}
function getModelValueFromString(val) {
- if (!specEditor.defined(val) || val==null || typeof val !== 'string') {
+ if (!specEditor.defined(val) || val == null || typeof val !== 'string') {
// only strings will have primitive inference applied
// (and this is only invoked when not in code mode)
return val;
@@ -810,7 +876,6 @@
let definition = scope.model.miscData.get('config').find(config => config.name === keyRef);
if (!definition) {
- // odd, no def'n for this key; infer
definition = {};
scope.getConfigWidgetMode(definition, localConfig[keyRef])
}
@@ -856,7 +921,7 @@
loadLocalConfigFromModel();
scope.state.config.add.value = '';
scope.state.config.add.open = false;
- scope.state.config.filter.values[ CONFIG_FILTERS[CONFIG_FILTERS.length - 1].id ] = true;
+ scope.state.config.filter.values[CONFIG_FILTERS[CONFIG_FILTERS.length - 1].id] = true;
scope.state.config.focus = name;
}
}
@@ -869,13 +934,68 @@
// If we need an integer, check if the value is a number
if (config.type === 'java.lang.Integer' && !angular.isNumber(value) && !(value instanceof Dsl)) {
- model.addIssue(Issue.builder().group('config').ref(key).message('<code>'+$sanitize(value)+'</code> is not a number').build());
+ model.addIssue(Issue.builder().group('config').ref(key).message('<code>' + $sanitize(value) + '</code> is not a number').build());
}
if (scope.state.config.codeModeError[key]) {
- model.addIssue(Issue.builder().group('config').ref(key).message('<code>'+$sanitize(value)+'</code> is not valid JSON').build());
+ model.addIssue(Issue.builder().group('config').ref(key).message('<code>' + $sanitize(value) + '</code> is not valid JSON').build());
}
});
}
+
+ /**
+ * The parameter data for each item is stored in multiple places, similar to configuration data:
+ *
+ * scope.parameters
+ * An array of values used/set by editor
+ *
+ * scope.model.parameters
+ * An array of values used in internal model
+ *
+ * scope.model.miscData.get('parameters')
+ * A list of parameters with their metadata, including derived widgetMode
+ */
+
+ function loadLocalParametersFromModel() {
+ let modelParams = scope.model.parameters;
+ let result = [];
+ for (let paramRef of modelParams) {
+ if (blueprintService.isReservedKey(paramRef.name)) {
+ continue; // skip
+ }
+ result.push(paramRef);
+ }
+ scope.parameters = result;
+ }
+
+ function getParameter(name) {
+ return scope.parameters.find(p => p.name === name);
+ }
+
+ function setModelFromLocalParameters() {
+ let localParams = scope.parameters;
+ let result = [];
+ for (let paramRef of localParams) {
+ if (angular.isUndefined(paramRef) || paramRef === null || paramRef.length < 1) {
+ continue;
+ }
+ result.push(paramRef);
+ }
+ scope.model.setParametersFromJson(result);
+ }
+
+ function addParameter() {
+ let name = scope.state.parameters.add.value;
+ if (name) {
+ let allParams = scope.model.miscData.get('parameters');
+ blueprintService.addParameterDefinition(allParams, name);
+ let param = allParams.find(p => p.name === name);
+ scope.model.addParameter(param);
+ loadLocalParametersFromModel();
+ scope.state.parameters.add.value = '';
+ scope.state.parameters.add.open = false;
+ scope.state.parameters.focus = name;
+ }
+ }
}
}
diff --git a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.template.html b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.template.html
index 31af6f8..a3ed9ae 100644
--- a/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.template.html
+++ b/ui-modules/blueprint-composer/app/components/spec-editor/spec-editor.template.html
@@ -51,6 +51,112 @@
</div>
</section>
+
+<!-- ENTITY PARAMETERS -->
+<br-collapsible ng-if="true" state="state.parameters.open"> <!-- the ng-if is needed to make state update?! -->
+ <heading>
+ Parameters
+ <span ng-if="getParameterIssues().length> 0" class="badge" ng-class="getBadgeClass(getParameterIssues())">{{getParameterIssues().length}}</span>
+ <span class="pull-right" ng-show="$parent.stateWrapped.state">
+ <span class="spec-toolbar-action" ng-class="{'active': state.parameters.filter.open}"><i class="fa fa-filter collapsible-action" title="Filter parameters" ng-click="$event.stopPropagation(); $event.preventDefault(); state.parameters.filter.open = !state.parameters.filter.open" ng-class="{'text-info': state.parameters.search.length > 0}"></i></span>
+ <span class="spec-toolbar-action"><i class="fa fa-plus collapsible-action" title="Add parameter" ng-click="$event.stopPropagation(); $event.preventDefault(); state.parameters.add.open = !state.parameters.add.open"></i></span>
+ </span>
+ </heading>
+
+ <fieldset uib-collapse="!state.parameters.filter.open" class="spec-configuration-filters">
+ <div class="form-group">
+ <input ng-model="state.parameters.search" type="text" class="form-control" placeholder="Search for parameter by name" auto-focus="state.parameters.filter.open" blur-on-enter />
+ </div>
+ </fieldset>
+
+ <fieldset uib-collapse="!state.parameters.add.open" class="spec-configuration-add">
+ <input auto-focus="state.parameters.add.open"
+ type="text"
+ autocomplete="off"
+ ng-model="state.parameters.add.value"
+ placeholder="Add a new parameter or open existing"
+ class="form-control"
+ uib-typeahead="parameter.name for parameter in state.parameters.add.list | filter:{name:$viewValue}"
+ typeahead-template-url="blueprint-composer/component/spec-editor/parameter-item.html"
+ typeahead-editable="true"
+ typeahead-show-hint="true"
+ typeahead-min-length="0"
+ typeahead-select-on-blur="true"
+ typeahead-on-select="onFocusOnParameter($item, $model, $label, $event)"
+ typeahead-no-results="noResults"
+ blur-on-enter />
+
+ <div ng-if="state.parameters.add.value.length > 0 && noResults" uib-dropdown uib-dropdown-toggle auto-close="disabled" is-open="true">
+ <ul class="dropdown-menu">
+ <!-- mimic real dropdown if nothing found -->
+ <li class="uib-typeahead-match"><a ng-click="addParameter()">
+ <div class="dropdown-item" ng-init="item = match.model">
+ <div class="dropdown-row">
+ <span ng-bind-html="state.parameters.add.value | uibTypeaheadHighlight:query" class="config-name"></span>
+ <i class="fa fa-fw fa-plus-square-o"></i>
+ </div>
+ </a></li>
+ </ul>
+ </div>
+ </fieldset>
+
+ <div class="spec-configuration">
+ <div class="spec-empty-state" ng-if="filteredItems.length === 0">
+ <div ng-if="model.miscData.get('parameters').length === 0">
+ <h4>No parameters</h4>
+ </div>
+ <div ng-if="model.miscData.get('parameters').length > 0">
+ <h4>No matching parameters</h4>
+ <p class="buttons">
+ <button class="btn btn-sm btn-default" ng-if="state.parameters.search.length > 0" ng-click="state.parameters.search = ''">Clear search</button>
+ <button class="btn btn-sm btn-success" ng-if="!state.parameters.filter.values.all" ng-click="state.parameters.filter.values.all = true">
+ <i class="fa fa-filter"></i> Display all parameter options
+ </button>
+ </p>
+ </div>
+ </div>
+
+ <form name="formSpecParameter" novalidate class="lightweight">
+ <div ng-repeat="item in (filteredItems = (model.miscData.get('parameters') | filter:{name:state.parameters.search} | orderBy:+priority)) track by item.name ">
+ <div class="form-group" ng-class="{'has-error': (model.issues | filter:{ref: item.name}:true).length > 0, 'used': getParameter(item.name) !== undefined}"
+ ng-switch="getParameterWidgetMode(item)"
+ tabindex="1"
+ auto-focus="state.parameters.focus === item.name"
+ auto-focus-listen-to-window="true"
+ auto-focus-not-if-within="true"
+ ng-focus="specEditor.recordParameterFocus(item)"
+ on-enter="specEditor.advanceControlInFormGroup">
+
+ <!-- have to hide it; excluding it conditionally via if doesn't play nice with switch -->
+ <div class="config-flex-row">
+ <label class="control-label" for="{{item.name}}">
+ <span class="label-spec-configuration">{{item.label || item.name}}</span>
+ <span class="info-spec-configuration">
+ <i class="fa fa-fw fa-info-circle" popover-trigger="'mouseenter'"
+ popover-title="{{item.label || item.name}}"
+ uib-popover-template="'blueprint-composer/component/spec-editor/parameter-info.html'"
+ popover-class="spec-editor-popover" popover-placement="top-left" popover-append-to-body="true"></i>
+ </span>
+ </label>
+
+ <span class="label-rhs-buttons">
+ <span class="spacer"> </span>
+ <span class="remove-spec-configuration" ng-if="getParameter(item.name) !== undefined">
+ <i class="fa fa-fw fa-eraser" ng-click="model.removeParameter(item.name)" aria-hidden="true" title="Clear parameter [{{item.name}}]"></i>
+ <span class="sr-only">Clear parameter [{{item.name}}]</span>
+ </span>
+ </span>
+
+ <!-- TODO use the code editor for defining parameter properties -->
+
+ <small ng-repeat="issue in model.issues | filter:{ref: item.name}:true" class="help-block issue" ng-bind-html="issue.message"></small>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+</br-collapsible>
+
<!-- ENTITY CONFIGURATION -->
<br-collapsible ng-if="true" state="state.config.open"> <!-- the ng-if is needed to make state update?! -->
<heading>
@@ -133,7 +239,7 @@
auto-focus="state.config.focus === item.name"
auto-focus-listen-to-window="true"
auto-focus-not-if-within="true"
- ng-focus="specEditor.recordFocus(item)"
+ ng-focus="specEditor.recordConfigFocus(item)"
on-enter="specEditor.advanceControlInFormGroup">
<div ng-if="specEditor.getCustomConfigWidgetMode(item) === 'enabled'" class="custom-config-widget">
<ng-include src="specEditor.getCustomConfigWidgetTemplate(item)" class="custom-config-widget"/>
@@ -180,10 +286,10 @@
<div class="control-value" ng-class="{ 'inline-control': item.widgetMode==='boolean', 'unset': !defined(config[item.name]), 'has-default': defined(item.defaultValue) && item.defaultValue!=null, 'code-mode-active': state.config.codeModeActive[item.name] }">
<div ng-switch-when="boolean" class="boolean">
<div class="btn-group btn-block" role="group">
- <button type="button" class="btn btn-xs btn-default" ng-class="{'btn-success active': config[item.name] === false, 'active': config[item.name] === undefined && item.defaultValue === false}" ng-click="config[item.name] = false" ng-focus="specEditor.recordFocus(item)">false</button>
- <button type="button" class="btn btn-xs btn-default" ng-class="{'btn-success active': config[item.name] === true, 'active': config[item.name] === undefined && item.defaultValue === true}" ng-click="config[item.name] = true" ng-focus="specEditor.recordFocus(item)">true</button>
+ <button type="button" class="btn btn-xs btn-default" ng-class="{'btn-success active': config[item.name] === false, 'active': config[item.name] === undefined && item.defaultValue === false}" ng-click="config[item.name] = false" ng-focus="specEditor.recordConfigFocus(item)">false</button>
+ <button type="button" class="btn btn-xs btn-default" ng-class="{'btn-success active': config[item.name] === true, 'active': config[item.name] === undefined && item.defaultValue === true}" ng-click="config[item.name] = true" ng-focus="specEditor.recordConfigFocus(item)">true</button>
<span class="input-group-btn dsl-wizard-button" ng-if="specEditor.isDslWizardButtonAllowed(item.name)">
- <a ui-sref="main.graphical.edit.dsl({entityId: model._id, for: item.name})" class="btn btn-xs btn-default" ng-class="{'btn-success active': config[item.name].length > 0}" title="Open in DSL editor" ng-focus="specEditor.recordFocus(item)"><i class="fa fa-bolt"></i></a>
+ <a ui-sref="main.graphical.edit.dsl({entityId: model._id, for: item.name})" class="btn btn-xs btn-default" ng-class="{'btn-success active': config[item.name].length > 0}" title="Open in DSL editor" ng-focus="specEditor.recordConfigFocus(item)"><i class="fa fa-bolt"></i></a>
</span>
</div>
</div>
@@ -192,7 +298,7 @@
<select ng-switch-when="java.lang.Enum"
ng-model="config[item.name]"
ng-options="s.value as (s.description + (item.defaultValue === s.value ? ' --- default' : '')) for s in item.possibleValues"
- ng-focus="specEditor.recordFocus(item)"
+ ng-focus="specEditor.recordConfigFocus(item)"
class="form-control rounded-edge"
name="{{item.name}}"
id="{{item.name}}"></select>
@@ -201,7 +307,7 @@
<div ng-switch-when="map"
ng-init="expandMode = 'default'" class="collection"
ng-class="{ 'open-when-unfocused': expandMode=='open' }">
- <p class="collection-toggle" ng-click="expandMode = cycleExpandMode(expandMode, 'map', item, state)" ng-focus="specEditor.recordFocus(item)"
+ <p class="collection-toggle" ng-click="expandMode = cycleExpandMode(expandMode, 'map', item, state)" ng-focus="specEditor.recordConfigFocus(item)"
ng-class="{ 'has-default': item.defaultValue && getObjectSize(item.defaultValue) }">
<i class="fa collection-caret" ng-class="{'fa-caret-square-o-down': expandMode=='closed', 'fa-caret-square-o-up': expandMode=='open', 'caret-default': expandMode=='default' }" aria-hidden="true" title="{{expandMode=='closed' ? 'Unpin' : expandMode=='open' ? 'Close (pin)' : 'Open (pin)'}} map"></i>
<span class="sr-only">{{expandMode=='closed' ? 'Unpin' : expandMode=='open' ? 'Close (pin)' : 'Open (pin)'}} map</span>
@@ -228,7 +334,7 @@
<span class="input-group">
<span class="main-control span-for-rounded-edge">
<input type="text" ng-model="config[item.name][mapKey]" class="form-control rounded-edge" placeholder="(empty)"
- ng-focus="specEditor.recordFocus(item)"
+ ng-focus="specEditor.recordConfigFocus(item)"
on-enter="specEditor.advanceControlInFormGroup" />
</span>
<span class="input-group-btn dsl-wizard-button rounded-edge" ng-if="specEditor.isDslWizardButtonAllowed(item.name, mapKey)">
@@ -240,7 +346,7 @@
<li class="collection-item collection-add input-group" ng-class="{'nonempty': nonempty(config[item.name])}">
<span class="main-control span-for-rounded-edge">
<input ng-model="newKey" type="text" placeholder="Add property key" class="form-control rounded-edge"
- ng-focus="specEditor.recordFocus(item)"
+ ng-focus="specEditor.recordConfigFocus(item)"
on-enter="specEditor.advanceOutToFormGroupInPanel" ng-blur="onAddMapProperty(item.name, newKey, $event); newKey = '';" required />
</span>
<span class="input-group-btn dsl-wizard-button rounded-edge" ng-if="specEditor.isDslWizardButtonAllowed(item.name, null, newKey)">
@@ -253,7 +359,7 @@
<div ng-switch-when="array" ng-switch-when-separator="|"
ng-init="expandMode = 'default'" class="collection"
ng-class="{ 'open-when-unfocused': expandMode=='open' }">
- <p class="collection-toggle" ng-click="expandMode = cycleExpandMode(expandMode, 'map', item, state)" ng-focus="specEditor.recordFocus(item)"
+ <p class="collection-toggle" ng-click="expandMode = cycleExpandMode(expandMode, 'map', item, state)" ng-focus="specEditor.recordConfigFocus(item)"
ng-class="{ 'has-default': item.defaultValue && item.defaultValue.length }">
<i class="fa collection-caret" ng-class="{'fa-caret-square-o-down': expandMode=='closed', 'fa-caret-square-o-up': expandMode=='open', 'caret-default': expandMode=='default' }" aria-hidden="true" title="{{expandMode=='closed' ? 'Unpin' : expandMode=='open' ? 'Close (pin)' : 'Open (pin)'}} list"></i>
<span class="sr-only">{{expandMode=='closed' ? 'Unpin' : expandMode=='open' ? 'Close (pin)' : 'Open (pin)'}} list</span>
@@ -279,10 +385,10 @@
<span class="input-group">
<span class="main-control span-for-rounded-edge">
<input type="text" ng-model="config[item.name][$index]" class="form-control rounded-edge" placeholder="(empty)"
- ng-focus="specEditor.recordFocus(item)"
+ ng-focus="specEditor.recordConfigFocus(item)"
on-enter="specEditor.advanceControlInFormGroup" />
</span>
- <span class="input-group-btn dsl-wizard-button rounded-edge" ng-if="specEditor.isDslWizardButtonAllowed(item.name, $index)" ng-focus="specEditor.recordFocus(item)">
+ <span class="input-group-btn dsl-wizard-button rounded-edge" ng-if="specEditor.isDslWizardButtonAllowed(item.name, $index)" ng-focus="specEditor.recordConfigFocus(item)">
<a ui-sref="main.graphical.edit.dsl({entityId: model._id, for: item.name, index: $index})" class="btn btn-default" title="Open in DSL editor"><i class="fa fa-bolt"></i></a>
</span>
</span>
@@ -292,7 +398,7 @@
<span class="input-group">
<span class="main-control span-for-rounded-edge">
<input ng-model="newItem" type="text" placeholder="Add item" class="form-control rounded-edge" auto-focus="expandMode != 'closed'"
- ng-focus="specEditor.recordFocus(item)"
+ ng-focus="specEditor.recordConfigFocus(item)"
on-enter="specEditor.advanceOutToFormGroupInPanel" ng-blur="onAddListItem(item.name, newItem, $event, $element); newItem = '';" required />
</span>
<span class="input-group-btn dsl-wizard-button rounded-edge" ng-if="specEditor.isDslWizardButtonAllowed(item.name, -1, newItem)">
@@ -308,7 +414,7 @@
<a ui-sref="main.graphical.edit.spec({entityId: model._id, specId: adjunct._id})"
class="open-entity-spec"
title="Open in spec editor"
- ng-focus="specEditor.recordFocus(item)"></a>
+ ng-focus="specEditor.recordConfigFocus(item)"></a>
<ng-include src="'blueprint-composer/component/spec-editor/adjunct.html'"></ng-include>
</div>
<a ng-if="!config[item.name][REPLACED_DSL_ENTITYSPEC]" ui-sref="main.graphical.edit.add({entityId: model._id, family: 'spec', configKey: item.name})" class="no-spec">
@@ -320,7 +426,7 @@
<span class="main-control span-for-rounded-edge">
<textarea ng-model="config[item.name]" class="form-control rounded-edge" name="{{item.name}}" id="{{item.name}}" auto-grow
placeholder="{{defined(config[item.name]) ? null : item.defaultValue=='' || item.defaultValue==null ? '(empty)' : item.defaultValue}}"
- ng-focus="specEditor.recordFocus(item)" on-enter="specEditor.advanceOutToFormGroupInPanel"></textarea>
+ ng-focus="specEditor.recordConfigFocus(item)" on-enter="specEditor.advanceOutToFormGroupInPanel"></textarea>
</span>
<span class="input-group-btn dsl-wizard-button rounded-edge" ng-if="specEditor.isDslWizardButtonAllowed(item.name)">
<a ui-sref="main.graphical.edit.dsl({entityId: model._id, for: item.name})" class="btn btn-default" title="Open in DSL editor"><i class="fa fa-bolt"></i></a>
@@ -447,6 +553,20 @@
</script>
+<!-- PARAMETER INFO TEMPLATE :: START -->
+<script type="text/ng-template" id="blueprint-composer/component/spec-editor/parameter-info.html" defer-to-preexisting-id="true">
+ <div class="config-item-quick-info">
+ <div class="quick-info-metadata">
+ <p><i class="mini-icon fa fa-fw fa-cog"></i> <samp class="type-symbolic-name">{{item.name}}</samp>
+ <span class="config-type label-color column-for-type oneline label label-success">{{item.type}}</span></p>
+ </div>
+ <p class="quick-info-description" ng-if="item.description" ng-bind-html="specEditor.descriptionHtml(item.description)"></p>
+ <div class="quick-info-metadata config-default" ng-if="item.defaultValue"></i>Default value: <samp>{{item.defaultValue}}</samp></div>
+ </div>
+
+</script>
+<!-- PARAMETER INFO TEMPLATE :: START-->
+
<!-- CONFIG INFO TEMPLATE :: START -->
<script type="text/ng-template" id="blueprint-composer/component/spec-editor/config-info.html" defer-to-preexisting-id="true">
<div class="config-item-quick-info">
diff --git a/ui-modules/blueprint-composer/app/components/util/model/entity.model.js b/ui-modules/blueprint-composer/app/components/util/model/entity.model.js
index 603eaa9..b0385b8 100644
--- a/ui-modules/blueprint-composer/app/components/util/model/entity.model.js
+++ b/ui-modules/blueprint-composer/app/components/util/model/entity.model.js
@@ -70,11 +70,11 @@
constructor() {
ID.set(this, Math.random().toString(36).slice(2));
CONFIG.set(this, new Map());
- PARAMETERS.set(this, new Map());
+ PARAMETERS.set(this, []);
METADATA.set(this, new Map());
ENRICHERS.set(this, new Map());
POLICIES.set(this, new Map());
- CHILDREN.set(this, new Array());
+ CHILDREN.set(this, []);
MISC_DATA.set(this, new Map());
MISC_DATA.get(this).set('issues', []);
this.family = EntityFamily.ENTITY.id;
@@ -484,7 +484,7 @@
* @returns {boolean}
*/
hasParameters() {
- return PARAMETERS.get(this).size > 0;
+ return PARAMETERS.get(this).length > 0;
}
/**
@@ -616,8 +616,7 @@
}
function addParameter(param) {
- let key = param.name;
- PARAMETERS.get(this).set(key, param);
+ PARAMETERS.get(this).push(param);
this.touch();
return this;
}
@@ -646,12 +645,19 @@
/**
* Remove an entry from brooklyn.parameters
- * @param {string} key
+ * @param {string} name
* @returns {Entity}
*/
-function removeParameter(key) {
- PARAMETERS.get(this).delete(key);
- this.touch();
+function removeParameter(name) {
+ if (this.hasParameters()) {
+ let paramIndex = PARAMETERS.get(this)
+ .filter(e => e.name === name)
+ .map(e => PARAMETERS.get(this).indexOf(e));
+ if (paramIndex.length > 0) {
+ let removed = PARAMETERS.get(this).splice(paramIndex[0], 1);
+ this.touch();
+ }
+ }
return this;
}
@@ -885,11 +891,11 @@
ID.set(this, Math.random().toString(36).slice(2));
this.removeLocation();
CONFIG.set(this, new Map());
- PARAMETERS.set(this, new Map());
+ PARAMETERS.set(this, []);
METADATA.set(this, new Map());
ENRICHERS.set(this, new Map());
POLICIES.set(this, new Map());
- CHILDREN.set(this, new Array());
+ CHILDREN.set(this, []);
MISC_DATA.set(this, new Map());
MISC_DATA.get(this).set('issues', []);
this.family = EntityFamily.ENTITY.id;
@@ -984,10 +990,10 @@
if (!Array.isArray(incomingModel)) {
throw new Error('Model parse error ... cannot add children as it must be an array')
}
- var children = new Array();
+ let children = [];
incomingModel.reduce((self, child)=> {
- var childEntity = new Entity();
+ let childEntity = new Entity();
childEntity.setEntityFromJson(child);
childEntity.parent = self;
children.push(childEntity);
@@ -1003,7 +1009,7 @@
*/
function setConfigFromJson(incomingModel) {
CONFIG.get(this).clear();
- var self = this;
+ let self = this;
Object.keys(incomingModel).forEach((key)=>(self.addConfig(key, incomingModel[key])));
this.touch();
}
@@ -1016,8 +1022,9 @@
if (!Array.isArray(incomingModel)) {
throw new Error('Model parse error ... cannot add parameters as it must be an array')
}
- PARAMETERS.get(this).clear();
- var self = this;
+ PARAMETERS.set(this, []);
+
+ let self = this;
incomingModel.map((param)=> {
self.addParameter(param);
});
@@ -1027,7 +1034,7 @@
function setMetadataFromJson(incomingModel) {
METADATA.get(this).clear();
- var self = this;
+ let self = this;
Object.keys(incomingModel).forEach((key)=> (self.addMetadata(key, incomingModel[key])));
this.touch();
}
@@ -1083,7 +1090,7 @@
}
function getParametersAsArray() {
- return Array.from(PARAMETERS.get(this).values());
+ return PARAMETERS.get(this);
}
/* "cleaning" here means: Dsl objects are toStringed, to the given depth (or infinite if depth<0);