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 15:12:53 UTC

[brooklyn-ui] 11/15: set from key or parameter working, with root or anywhere (optionally with type) or ancestors (optionally with type)

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 0456306abca63ae1b69962d0f340b7febe23ace6
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Mon Apr 26 19:29:28 2021 +0100

    set from key or parameter working, with root or anywhere (optionally with type) or ancestors (optionally with type)
---
 docs/basic-with-constraint.bom                     |  17 +--
 .../app/components/quick-fix/quick-fix.js          | 166 ++++++++++++++-------
 .../app/components/util/model/entity.model.js      |  10 ++
 3 files changed, 130 insertions(+), 63 deletions(-)

diff --git a/docs/basic-with-constraint.bom b/docs/basic-with-constraint.bom
index 3ca3e3c..0f1a2db 100644
--- a/docs/basic-with-constraint.bom
+++ b/docs/basic-with-constraint.bom
@@ -37,21 +37,20 @@ brooklyn.catalog:
         message-regex: cannot both be set
 
       - key: post_code
-        fix: set_from_parameter
+        fix: set_from_key
         message-regex: required
 
-        source-mode: suggested
+        source-key: postal_code
         source-hierarchy: root
-        source-types: [ org.apache.brooklyn.api.entity.Application ]
-        source-parameter: postal_code
-        source-constraints:
-        - required
+        source-key-createable: true
+        source-key-parameter-definition:
+          constraints:
+          - required
 
       - key: post_code
-        fix: set_from_config_key
+        fix: set_from_key
         message-regex: required
 
-        source-mode: enforced
-        source-types: [ basic-with-constraint ]
         source-key: post_code
         source-hierarchy: anywhere
+        source-types: [ basic-with-constraint ]
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 049a713..d703f11 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
@@ -90,76 +90,134 @@ const QUICK_FIX_PROPOSERS = {
             proposals.clear_config.issues.push(issue);
         },
     },
-    set_from_parameter: {
-        propose: proposeSetFrom('parameter')
-
-      // - key: post_code
-      //   fix: set_from_parameter
-      //   message-regex: required
-      //   source-mode: suggested
-      //   source-hierarchy: root
-      //   source-types: [ org.apache.brooklyn.api.entity.Application ]
-      //   source-parameter: postal_code
-      //   source-constraints:
-      //   - required
-
-    },
-    set_from_config_key: {
-        propose: proposeSetFrom('config')
-
+    set_from_key: {
+        propose: proposeSetFrom()
         // - key: post_code
-        //   fix: set_from_config_key
+        //   fix: set_from_key
         //   message-regex: required
-        //   source-mode: enforced
-        //   source-types: [ basic-with-constraint ]
-        //   source-key: post_code
-        //   source-hierarchy: anywhere
+        //
+        //   source-key: postal_code    # required, custom
+        //
+        //   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
+        //
+        //   source-key-createable: true         # whether a parameter can be created or a key/param must already exist there (default the latter, ie false)
+        //   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
 
-    }
+    },
 };
 
-function proposeSetFrom(sourceType) {
+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);
+            return;
+        }
+
         if (!proposals) proposals = {};
 
-        let sourceNode = {
-            id: 'root',
-            name: 'the application root node',
-            entity: entity.getApplication(),
-        };
+        let createable = qfdef['source-key-createable'];
 
-        if (sourceType === 'parameter') {
-            let params = sourceNode.entity.getParametersAsArray();
-            console.log("params", params);
-        }
+        // TODO if root param is required, show error
+        // TODO make default id containts type name
+        // TODO show default id if no id present
+        // TODO if id is changed, update all refs
+        // TODO allow graphically selectable
+
+        let considerNode = (sourceNode) => {
+            if (qfdef['source-types']) {
+                // TODO would be nice to store super-types of entity in miscData and filter based on those
+                if (!qfdef['source-types'].includes(sourceNode.entity.type)) {
+                    // wrong type
+                    return;
+                }
+            }
+
+            if (sourceNode.entity._id === entity._id && ckey === issue.ref) {
+                // skip proposal for recursive definition
+                return;
+            }
 
-        let key = 'set_from_'+sourceType+'_'+sourceNode.id;
-        if (!proposals[key]) {
-            proposals[key] = {
-                text: "Set from a new "+sourceType+" on "+sourceNode.name,
-                tooltip: "This will create a "+sourceType+" on "+sourceNode.name+" and fix this error by setting it equal to that "+sourceType,
-                issues: [],
-                apply: (issue, entity) => {
-                    entity = (entity || issue.entity);
-                    console.log("TODO do this; NB issue invoked wrt", entity, qfdef);
-                    if (sourceType === 'parameter') {
-                        if (!sourceNode.entity.getParameterNamed(qfdef['source-parameter'])) {
-                            sourceNode.entity.addParameter({
-                                name: qfdef['source-parameter'],
-                                constraints: qfdef['source-constraints']
-                            });
+            let hasKey = sourceNode.entity.config[ckey] || (sourceNode.entity.miscData.get("config") || []).find(c => c && c.name === ckey);
+            let hasParam = sourceNode.entity.getParameterNamed(ckey);
+
+            let existing = hasKey || hasParam;
+            let create = !existing && createable;
+
+            if (!existing && !create) {
+                // no proposal available (cannot create)
+                return;
+            }
+
+            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 (sourceNode.create_key) {
+                    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 (sourceNode.create_key) {
+                            // check again so we only create once
+                            let hasParam = sourceNode.entity.getParameterNamed(ckey);
+                            if (!hasParam) {
+                                sourceNode.entity.addParameter(Object.assign(
+                                    {name: ckey,},
+                                    qfdef['source-key-parameter-definition'] || {}
+                                ));
+                            }
                         }
                         if (!sourceNode.entity.id) {
-                            // TODO
-                            sourceNode.entity.id = 'id_XXX';
+                            sourceNode.entity.id = sourceNode.entity._id;
                         }
-                        entity.addConfig(issue.ref, '$brooklyn:component("'+sourceNode.entity.id+'").config("'+qfdef['source-parameter']+'")');
+
+                        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(),
+                    });
+        } else if (qfdef['source-hierarchy']=='anywhere' || (!qfdef['source-hierarchy'] && qfdef['source-types'])) {
+            entity.getApplication().visitWithDescendants(entity => considerNode({ entity }));
+        } else if (qfdef['source-hierarchy']=='ancestors') {
+            entity.visitWithAncestors(entity => considerNode({ entity }));
+        } else {
+            console.warn("Unsupported source-hierarchy in quick-fix", qfdef);
         }
-        proposals[key].issues.push(issue);
+
     };
 }
 
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 f8afc28..b844450 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
@@ -563,6 +563,16 @@ export class Entity {
     toString() {
         return 'Entity :: id = [' + this._id + ']' + (this.hasType() ? ' type = [' + this.type + ']' : '');
     }
+
+    visitWithDescendants(fn) {
+        fn(this);
+        this.children.forEach(c => c.visitWithDescendants(fn));
+    }
+
+    visitWithAncestors(fn) {
+        fn(this);
+        if (this.parent) this.parent.visitWithAncestors(fn);
+    }
 }
 
 Entity.prototype.setEntityFromJson = setEntityFromJson;