You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2021/04/27 23:45:55 UTC
[brooklyn-ui] 04/05: add quick fix for proposing from a template
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 e67cc9331111c83d2f12aeb0b6c97026d00073b9
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Wed Apr 28 00:29:55 2021 +0100
add quick fix for proposing from a template
---
docs/basic-with-constraint.bom | 8 ++
.../app/components/quick-fix/quick-fix.js | 117 +++++++++++++++++++--
2 files changed, 118 insertions(+), 7 deletions(-)
diff --git a/docs/basic-with-constraint.bom b/docs/basic-with-constraint.bom
index a3297b1..5457a2a 100644
--- a/docs/basic-with-constraint.bom
+++ b/docs/basic-with-constraint.bom
@@ -65,3 +65,11 @@ brooklyn.catalog:
source-key: post_code # will match the key
source-hierarchy: anywhere # anywhere
source-types: [ basic-with-constraint ] # of this type
+
+ - key: post_code
+ fix: set_from_template
+ message-regex: required
+
+ template: ${application}-${entity} # required, the template, supporting vars application, application.id, entity, entity.name, entity._id
+ preview: "Set ${entity.type} post_code '${application}-<entity_name_or_id>'" # optional, summary for button, grouping fixes, and filtering (template rules applied to this, skipped if not applicable)
+ sanitize: _ # optional, sanitize as specified, eg _ or - or '.' to replace non-alphanumeric chars with that
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 1ee28cb..87ae979 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
@@ -91,12 +91,13 @@ const QUICK_FIX_PROPOSERS = {
},
},
set_from_key: {
- propose: proposeSetFrom()
+ propose: proposeSetFromKey()
// - key: post_code
// fix: set_from_key
// message-regex: required
//
- // source-key: postal_code # required, custom
+ // source-key: postal_code # one of these is required
+ // source-key-regex: ^postal_code($|_.*)
//
// source-hierarchy: root # optional, root|anywhere|ancestors -- default is root if no source-types given, anywhere if source-types are given
// source-types: [ org.apache.brooklyn.api.entity.Application ] # types to filter by
@@ -105,13 +106,19 @@ const QUICK_FIX_PROPOSERS = {
// source-key-parameter-definition: # if createable and did not exist, extra things to add to definition
// constraints:
// - required
-
- // source-mode: suggested | enforced # (enhancement, not supported) could allow user to pick the type and/or key/param name
-
},
+ set_from_template: {
+ propose: proposeSetFromTemplate(),
+ // - key: post_code
+ // fix: set_from_template
+ // message-regex: required
+ // template: ${application}-${entity} # required, the template, supporting vars application, application.id, entity, entity.name, entity._id
+ // preview: "Set post_code '${application}_<entity_name_or_id>'" # optional, summary for button, grouping fixes, and filtering (template rules applied to this, skipped if not applicable)
+ // sanitize: _ # optional, sanitize as specified, eg _ or - or '.' to replace non-alphanumeric chars with that
+ }
};
-function proposeSetFrom() {
+function proposeSetFromKey() {
return function (qfdef, issue, entity, blueprintService, proposals) {
if (!issue.ref) return;
@@ -187,7 +194,7 @@ function proposeSetFrom() {
return;
}
- let pkey = 'set_from_' + sourceNode.id + '_' + ckey;
+ let pkey = 'set_from_key_' + sourceNode.id + '_' + ckey;
if (!proposals[pkey]) {
if (create) {
proposals[pkey] = {
@@ -243,6 +250,102 @@ function proposeSetFrom() {
};
}
+function proposeSetFromTemplate() {
+ return function (qfdef, issue, entity, blueprintService, proposals) {
+ if (!issue.ref) return;
+
+ let template = qfdef['template'];
+ if (!template) {
+ console.warn("Missing 'template' on hint", qfdef);
+ return;
+ }
+
+ let sanitize = qfdef['sanitize'];
+ let sanitizeFn = s => {
+ if (!sanitize) return s;
+ return s.replace(/\W+/g, sanitize);
+ }
+
+ if (!proposals) proposals = {};
+
+ function replace(s, keyword, fn, skipSanitize) {
+ if (!s) return null;
+ let p = "${"+keyword+"}";
+ if (s.includes(p)) {
+ let v = fn();
+ if (v) {
+ if (!skipSanitize) v = sanitizeFn(v);
+ do {
+ s = s.replace(p, v);
+ } while (s.includes(p));
+ } else {
+ return null;
+ }
+ }
+ return s;
+ }
+
+ function replaceTemplate(result, s, x, idFn, isPreview) {
+ let idLastFn = () => {
+ let last = x.id;
+ let takeLast = last || !isPreview;
+ last = last || idFn(s,x);
+ if (takeLast) last = last.replace(/^.*\W+(\w+\W*)/, '$1');
+ return last;
+ };
+ result = replace(result, s, () => x.name || idLastFn(), isPreview && !x.name && !x.id);
+ result = replace(result, s+".name", () => x.name);
+ result = replace(result, s+".nameOrType", () => x.name || x.miscData.get('typeName') || x.type);
+ result = replace(result, s+".typeName", () => x.miscData.get('typeName') || x.type);
+ result = replace(result, s+".type", () => x.type || x.miscData.get('typeName'));
+ result = replace(result, s+".id", () => x.id || idFn(s,x));
+ // takes the last word of the ID
+ result = replace(result, s+".idLast", idLastFn, isPreview);
+ result = replace(result, s+"._id", () => x._id);
+ return result;
+ }
+
+ let idFnForPreview = (s,x) => "<"+s+" ID, changed from "+x._id+">";
+ let preview = qfdef['preview'] || "Set '"+template+"'";
+ preview = replaceTemplate(preview, "entity", entity, idFnForPreview, true);
+ preview = replaceTemplate(preview, "application", entity.getApplication(), idFnForPreview, true);
+
+ if (preview) {
+ let pkey = 'set_from_template_' + preview;
+ if (!proposals[pkey]) {
+ proposals[pkey] = {
+ text: preview,
+ tooltip: "This will fix the error by setting the value here based on a template." +
+ (sanitize ? " The result will be sanitized using '" + sanitize + "'." : ""),
+ };
+
+ Object.assign(proposals[pkey], {
+ issues: [],
+ apply: (issue, entity) => {
+ entity = (entity || issue.entity);
+ let result = template;
+ let idFnForActual = (s, x) => {
+ blueprintService.populateId(x);
+ return x.id;
+ };
+ result = replaceTemplate(result, "entity", entity, idFnForActual);
+ result = replaceTemplate(result, "application", entity.getApplication(), idFnForActual);
+ if (!result) {
+ console.warn("Could not apply quick fix: template '"+template+"' not valid at entity", entity);
+ } else {
+ entity.addConfig(issue.ref, result);
+ }
+ }
+ });
+ }
+ if (proposals[pkey]) {
+ proposals[pkey].issues.push(issue);
+ }
+ }
+
+ };
+}
+
export function getQuickFixProposer(type) {
return QUICK_FIX_PROPOSERS[type];
}