This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-ui.git
commit 27ae044bfb7153ac70ea4e4d46fcbf95ac3b4fe7 Author: Alex Heneveld <[email protected]> AuthorDate: Tue Apr 27 21:33:48 2021 +0100 quick fix supports regexes to match params, and more * support regex to match existing params * always refer to root node as root * fix bug in parameter creation (newly caused) * fix bug in "Add parameter" button visibility (longstanding) --- docs/basic-with-constraint.bom | 25 ++-- .../app/components/quick-fix/quick-fix.js | 137 ++++++++++++--------- .../spec-editor/spec-editor.template.html | 9 +- .../app/components/util/model/entity.model.js | 7 +- 4 files changed, 108 insertions(+), 70 deletions(-) diff --git a/docs/basic-with-constraint.bom b/docs/basic-with-constraint.bom index 0f1a2db..a3297b1 100644 --- a/docs/basic-with-constraint.bom +++ b/docs/basic-with-constraint.bom @@ -36,21 +36,32 @@ brooklyn.catalog: fix: clear_config message-regex: cannot both be set - - key: post_code + - # set from existing key matching [.*_|]postal_code[|_.*] on ancestor + key: post_code fix: set_from_key message-regex: required source-key: postal_code - source-hierarchy: root - source-key-createable: true + source-key-regex: (_|^)postal_code(_|$) # will match e.g. cust1_postal_code and postal_core_north but not postal_codex + source-hierarchy: ancestors # on self or any ancestor + + - # create key postal_code at root + key: post_code + fix: set_from_key + message-regex: required + + source-key: postal_code + source-key-createable: true # will create if not present + source-hierarchy: root # but only at root source-key-parameter-definition: constraints: - required - - key: post_code + - # use this key on any other entity of the same type + key: post_code fix: set_from_key message-regex: required - source-key: post_code - source-hierarchy: anywhere - source-types: [ basic-with-constraint ] + source-key: post_code # will match the key + source-hierarchy: anywhere # anywhere + source-types: [ basic-with-constraint ] # of this type diff --git a/ui-modules/blueprint-composer/app/components/quick-fix/quick-fix.js b/ui-modules/blueprint-composer/app/components/quick-fix/quick-fix.js index 16cbac1..27f175a 100644 --- a/ui-modules/blueprint-composer/app/components/quick-fix/quick-fix.js +++ b/ui-modules/blueprint-composer/app/components/quick-fix/quick-fix.js @@ -114,9 +114,10 @@ function proposeSetFrom() { return function (qfdef, issue, entity, proposals) { if (!issue.ref) return; - let ckey = qfdef['source-key']; - if (!ckey) { - console.warn("Missing required 'source-key' on hint", qfdef); + let ckey_exact = qfdef['source-key']; + let ckey_regex = qfdef['source-key-regex']; + if (!ckey_exact && !ckey_regex) { + console.warn("Missing at least one of 'source-key' or 'source-key-regex' on hint", qfdef); return; } @@ -143,76 +144,96 @@ function proposeSetFrom() { } } - if (sourceNode.entity._id === entity._id && ckey === issue.ref) { - // skip proposal for recursive definition - return; - } + let contenders = {}; + if (ckey_exact) { + let exactKey = sourceNode.entity.config[ckey_exact] || (sourceNode.entity.miscData.get("config") || []).find(c => c.name === ckey_exact); + // don't think we need to check params -- sourceNode.entity.getParameterNamed(ckey) -- as they should be in config - let hasKey = sourceNode.entity.config[ckey] || (sourceNode.entity.miscData.get("config") || []).find(c => c && c.name === ckey); - let hasParam = sourceNode.entity.getParameterNamed(ckey); + if (exactKey) contenders[ckey_exact] = true; + } + let create = !Object.keys(contenders).length && createable && ckey_exact; + if (create) { + contenders[ckey_exact] = true; + } - let existing = hasKey || hasParam; - let create = !existing && createable; + if (ckey_regex) { + let r = new RegExp(ckey_regex); + Object.keys(sourceNode.entity.config).forEach(k => { + if (r.test(k)) contenders[k] = true; + }); + (sourceNode.entity.miscData.get("config") || []).forEach(c => { + if (r.test(c.name)) contenders[c.name] = true; + }); + } + console.log("result of regex at", ckey_regex, sourceNode, contenders); - if (!existing && !create) { + if (!Object.keys(contenders).length) { // no proposal available (cannot create) return; } + if (!sourceNode.entity.parent) { + sourceNode.id = sourceNode.id || 'root'; + sourceNode.name = sourceNode.name || sourceNode.entity.name || 'the application root node'; + } + sourceNode.id = sourceNode.id || sourceNode.entity.id || sourceNode.entity._id; sourceNode.name = sourceNode.name || sourceNode.entity.name || - ((sourceNode.entity.type || "Unnamed item") + " " + "(" + (sourceNode.entity.id || sourceNode.entity._id) +")"); - - let pkey = 'set_from_' + sourceNode.id + '_' + ckey; - if (!proposals[pkey]) { - if (create) { - proposals[pkey] = { - text: "Set from new parameter '" + ckey + "' on " + sourceNode.name, - tooltip: "This will fix the error by setting the value here equal to the value of a new parameter '" + ckey + "' created on " + sourceNode.name - + ". The value of that parameter may need to be set in order to deploy this.", - }; - } else { - proposals[pkey] = { - text: "Set from '" + ckey + "' on " + sourceNode.name, - tooltip: "This will fix the error by setting the value here equal to the value of " + - sourceNode.target_mode + - " '" + ckey + "' on " + sourceNode.name, - }; + ((sourceNode.entity.type || "Unnamed item") + " " + "(" + (sourceNode.entity.id || sourceNode.entity._id) + ")"); + + Object.keys(contenders).forEach(ckey => { + if (sourceNode.entity._id === entity._id && ckey === issue.ref) { + // skip proposal for recursive definition + return; } - Object.assign(proposals[pkey], { - issues: [], - apply: (issue, entity) => { - if (create) { - // check again so we only create once - let hasParam = sourceNode.entity.getParameterNamed(ckey); - if (!hasParam) { - sourceNode.entity.addParameterDefinition(Object.assign( - {name: ckey,}, - qfdef['source-key-parameter-definition'], - )); + let pkey = 'set_from_' + sourceNode.id + '_' + ckey; + if (!proposals[pkey]) { + if (create) { + proposals[pkey] = { + text: "Set from new parameter '" + ckey + "' on " + sourceNode.name, + tooltip: "This will fix the error by setting the value here equal to the value of a new parameter '" + ckey + "' created on " + sourceNode.name + + ". The value of that parameter may need to be set in order to deploy this.", + }; + } else { + proposals[pkey] = { + text: "Set from '" + ckey + "' on " + sourceNode.name, + tooltip: "This will fix the error by setting the value here equal to the value of " + + sourceNode.target_mode + + " '" + ckey + "' on " + sourceNode.name, + }; + } + + Object.assign(proposals[pkey], { + issues: [], + apply: (issue, entity) => { + if (create) { + // check again so we only create once + let hasParam = sourceNode.entity.getParameterNamed(ckey); + if (!hasParam) { + sourceNode.entity.addParameterDefinition(Object.assign( + {name: ckey,}, + qfdef['source-key-parameter-definition'], + )); + } + } + if (!sourceNode.entity.id) { + sourceNode.entity.id = sourceNode.entity._id; } - } - if (!sourceNode.entity.id) { - sourceNode.entity.id = sourceNode.entity._id; - } - entity = (entity || issue.entity); - entity.addConfig(issue.ref, '$brooklyn:component("' + sourceNode.entity.id + '").config("' + ckey + '")'); - } - }); - } - if (proposals[pkey]) { - proposals[pkey].issues.push(issue); - } - }; + entity = (entity || issue.entity); + entity.addConfig(issue.ref, '$brooklyn:component("' + sourceNode.entity.id + '").config("' + ckey + '")'); + } + }); + } + if (proposals[pkey]) { + proposals[pkey].issues.push(issue); + } + }); + } if (qfdef['source-hierarchy']=='root' || (!qfdef['source-hierarchy'] && !qfdef['source-types'])) { - considerNode({ - id: 'root', - name: 'the application root node', - entity: entity.getApplication(), - }); + considerNode({ entity: entity.getApplication() }); } else if (qfdef['source-hierarchy']=='anywhere' || (!qfdef['source-hierarchy'] && qfdef['source-types'])) { entity.getApplication().visitWithDescendants(entity => considerNode({ entity })); } else if (qfdef['source-hierarchy']=='ancestors') { 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 6050219..bfe3616 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 @@ -97,16 +97,19 @@ <div ng-if="parameters.length === 0"> <h4>No parameters</h4> <p class="buttons"> - <button class="btn btn-sm btn-success" ng-click="specEditor.addParameter(state.parameters.search)"> - <i class="fa fa-plus"></i> Add parameter + <button class="btn btn-sm btn-success" ng-click="specEditor.addParameter(state.parameters.search)" ng-if="state.parameters.search"> + <i class="fa fa-plus"></i> Add '{{state.parameters.search}}' </button> </p> + <p ng-if="!state.parameters.search"> + Search for a parameter to add one + </p> </div> <div ng-if="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-click="specEditor.addParameter(state.parameters.search)"> + <button class="btn btn-sm btn-success" ng-click="specEditor.addParameter(state.parameters.search)" ng-if="state.parameters.search"> <i class="fa fa-plus"></i> Add '{{state.parameters.search}}' </button> </p> 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 71a5912..d61fa60 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 @@ -685,11 +685,14 @@ function addParameterDefinition(param, overwrite, skipUpdatesDuringBatch) { let allParams = this.miscDataOrDefault('parametersMap', {}); if (param) { if (typeof param === 'string') { - param = {name: key, type: 'string'}; + param = {name: param, type: 'string'}; overwrite = false; } let key = (param || {}).name; - if (!key) throw new Error("'name' field must be included when adding parameter"); + if (!key) { + console.warn("Invalid parameter definition to add", typeof param, param); + throw new Error("'name' field must be included when adding parameter"); + } param = allParams[key] = Object.assign(allParams[key] || {}, param, overwrite ? null : allParams[key]);
