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 <[email protected]> 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]; }
