From adb71ecfe7b2a87e372d207837c769017f49d18a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 23 Mar 2018 10:41:29 +0200 Subject: [PATCH] Rule Node Configuration --- .../AnnotationComponentDiscoveryService.java | 9 +- .../src/main/resources/thingsboard.yml | 2 +- .../rule/engine/api/NodeConfiguration.java | 22 +++ .../thingsboard/rule/engine/api/RuleNode.java | 5 +- .../src/main/resources/EmptyNodeConfig.json | 2 - .../main/resources/EmptyNodeDescriptor.json | 2 - .../rule/engine/filter/TbJsFilterNode.java | 1 + .../filter/TbJsFilterNodeConfiguration.java | 10 +- .../rule/engine/filter/TbJsSwitchNode.java | 1 + .../filter/TbJsSwitchNodeConfiguration.java | 17 +- .../engine/filter/TbMsgTypeFilterNode.java | 1 + .../TbMsgTypeFilterNodeConfiguration.java | 11 +- .../engine/metadata/TbGetAttributesNode.java | 1 + .../TbGetAttributesNodeConfiguration.java | 13 +- .../metadata/TbGetCustomerAttributeNode.java | 1 + .../TbGetEntityAttrNodeConfiguration.java | 14 +- .../TbGetRelatedAttrNodeConfiguration.java | 19 +- .../metadata/TbGetRelatedAttributeNode.java | 1 + .../metadata/TbGetTenantAttributeNode.java | 1 + .../transform/TbChangeOriginatorNode.java | 1 + .../TbChangeOriginatorNodeConfiguration.java | 14 +- .../engine/transform/TbTransformMsgNode.java | 1 + .../TbTransformMsgNodeConfiguration.java | 11 +- ui/src/app/api/rule-chain.service.js | 25 +-- .../components/json-object-edit.directive.js | 165 ++++++++++++++++++ ui/src/app/components/json-object-edit.scss | 35 ++++ .../app/components/json-object-edit.tpl.html | 34 ++++ ui/src/app/layout/index.js | 4 +- ui/src/app/locale/locale.constant.js | 1 + ui/src/app/rulechain/rulechain.controller.js | 82 ++++----- .../app/rulechain/rulenode-fieldset.tpl.html | 5 + ui/src/app/rulechain/rulenode.directive.js | 2 + ui/src/app/rulechain/rulenode.scss | 22 +++ ui/src/app/rulechain/rulenode.tpl.html | 2 +- ui/src/scss/main.scss | 18 ++ 35 files changed, 483 insertions(+), 72 deletions(-) create mode 100644 rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java delete mode 100644 rule-engine/rule-engine-api/src/main/resources/EmptyNodeConfig.json delete mode 100644 rule-engine/rule-engine-api/src/main/resources/EmptyNodeDescriptor.json create mode 100644 ui/src/app/components/json-object-edit.directive.js create mode 100644 ui/src/app/components/json-object-edit.scss create mode 100644 ui/src/app/components/json-object-edit.tpl.html create mode 100644 ui/src/app/rulechain/rulenode.scss diff --git a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java index 52d7d7d80c..479f424e93 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java @@ -180,7 +180,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe return scannedComponent; } - private NodeDefinition prepareNodeDefinition(RuleNode nodeAnnotation) throws IOException { + private NodeDefinition prepareNodeDefinition(RuleNode nodeAnnotation) throws Exception { NodeDefinition nodeDefinition = new NodeDefinition(); nodeDefinition.setDetails(nodeAnnotation.nodeDetails()); nodeDefinition.setDescription(nodeAnnotation.nodeDescription()); @@ -188,9 +188,10 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe nodeDefinition.setOutEnabled(nodeAnnotation.outEnabled()); nodeDefinition.setRelationTypes(nodeAnnotation.relationTypes()); nodeDefinition.setCustomRelations(nodeAnnotation.customRelations()); - String defaultConfigResourceName = nodeAnnotation.defaultConfigResource(); - nodeDefinition.setDefaultConfiguration(mapper.readTree( - Resources.toString(Resources.getResource(defaultConfigResourceName), Charsets.UTF_8))); + Class configClazz = nodeAnnotation.configClazz(); + NodeConfiguration config = configClazz.newInstance(); + NodeConfiguration defaultConfiguration = config.defaultConfiguration(); + nodeDefinition.setDefaultConfiguration(mapper.valueToTree(defaultConfiguration)); return nodeDefinition; } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 27585212db..1df2f1cf31 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -234,7 +234,7 @@ caffeine: specs: relations: timeToLiveInMinutes: 1440 - maxSize: 100000 + maxSize: 0 deviceCredentials: timeToLiveInMinutes: 1440 maxSize: 100000 diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java new file mode 100644 index 0000000000..5e4c4b5399 --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2018 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.api; + +public interface NodeConfiguration { + + NodeConfiguration defaultConfiguration(); + +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java index f8e0fa2e29..16170347a7 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java @@ -35,15 +35,16 @@ public @interface RuleNode { String nodeDetails(); + Class configClazz(); + boolean inEnabled() default true; boolean outEnabled() default true; ComponentScope scope() default ComponentScope.TENANT; - String defaultConfigResource() default "EmptyNodeConfig.json"; - String[] relationTypes() default {"Success", "Failure"}; boolean customRelations() default false; + } diff --git a/rule-engine/rule-engine-api/src/main/resources/EmptyNodeConfig.json b/rule-engine/rule-engine-api/src/main/resources/EmptyNodeConfig.json deleted file mode 100644 index 7a73a41bfd..0000000000 --- a/rule-engine/rule-engine-api/src/main/resources/EmptyNodeConfig.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} \ No newline at end of file diff --git a/rule-engine/rule-engine-api/src/main/resources/EmptyNodeDescriptor.json b/rule-engine/rule-engine-api/src/main/resources/EmptyNodeDescriptor.json deleted file mode 100644 index 7a73a41bfd..0000000000 --- a/rule-engine/rule-engine-api/src/main/resources/EmptyNodeDescriptor.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java index c85d4807e0..07b166db68 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java @@ -30,6 +30,7 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback; @RuleNode( type = ComponentType.FILTER, name = "script", relationTypes = {"True", "False", "Failure"}, + configClazz = TbJsFilterNodeConfiguration.class, nodeDescription = "Filter incoming messages using JS script", nodeDetails = "Evaluate incoming Message with configured JS condition. " + "If True - send Message via True chain, otherwise False chain is used." + diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeConfiguration.java index bf543e3276..3b19c7c641 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeConfiguration.java @@ -16,9 +16,17 @@ package org.thingsboard.rule.engine.filter; import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; @Data -public class TbJsFilterNodeConfiguration { +public class TbJsFilterNodeConfiguration implements NodeConfiguration { private String jsScript; + + @Override + public TbJsFilterNodeConfiguration defaultConfiguration() { + TbJsFilterNodeConfiguration configuration = new TbJsFilterNodeConfiguration(); + configuration.setJsScript("msg.passed < 15 && msg.name === 'Vit' && meta.temp == 10 && msg.bigObj.prop == 42;"); + return configuration; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java index faf97b4e50..c1236a4653 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java @@ -31,6 +31,7 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback; @RuleNode( type = ComponentType.FILTER, name = "switch", customRelations = true, + configClazz = TbJsSwitchNodeConfiguration.class, nodeDescription = "Route incoming Message to one or multiple output chains", nodeDetails = "Node executes configured JS script. Script should return array of next Chain names where Message should be routed. " + "If Array is empty - message not routed to next Node. " + diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeConfiguration.java index 331302d542..b354c7199f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeConfiguration.java @@ -15,14 +15,29 @@ */ package org.thingsboard.rule.engine.filter; +import com.google.common.collect.Sets; import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; import java.util.Set; @Data -public class TbJsSwitchNodeConfiguration { +public class TbJsSwitchNodeConfiguration implements NodeConfiguration { private String jsScript; private Set allowedRelations; private boolean routeToAllWithNoCheck; + + @Override + public TbJsSwitchNodeConfiguration defaultConfiguration() { + TbJsSwitchNodeConfiguration configuration = new TbJsSwitchNodeConfiguration(); + configuration.setJsScript("function nextRelation(meta, msg) {\n" + + " return ['one','nine'];" + + "};\n" + + "\n" + + "nextRelation(meta, msg);"); + configuration.setAllowedRelations(Sets.newHashSet("one", "two")); + configuration.setRouteToAllWithNoCheck(false); + return configuration; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java index 7a6f9fdbee..3a86c25afb 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java @@ -28,6 +28,7 @@ import org.thingsboard.server.common.msg.TbMsg; @RuleNode( type = ComponentType.FILTER, name = "message type", + configClazz = TbMsgTypeFilterNodeConfiguration.class, nodeDescription = "Filter incoming messages by Message Type", nodeDetails = "Evaluate incoming Message with configured JS condition. " + "If incoming MessageType is expected - send Message via Success chain, otherwise Failure chain is used.") diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java index 3b7ba9055e..a2e1b179f0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java @@ -16,15 +16,24 @@ package org.thingsboard.rule.engine.filter; import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import java.util.Arrays; +import java.util.Collections; import java.util.List; /** * Created by ashvayka on 19.01.18. */ @Data -public class TbMsgTypeFilterNodeConfiguration { +public class TbMsgTypeFilterNodeConfiguration implements NodeConfiguration { private List messageTypes; + @Override + public TbMsgTypeFilterNodeConfiguration defaultConfiguration() { + TbMsgTypeFilterNodeConfiguration configuration = new TbMsgTypeFilterNodeConfiguration(); + configuration.setMessageTypes(Arrays.asList("GET_ATTRIBUTES","POST_ATTRIBUTES","POST_TELEMETRY","RPC_REQUEST")); + return configuration; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java index 6228206da8..69ee9d7c79 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java @@ -38,6 +38,7 @@ import static org.thingsboard.server.common.data.DataConstants.*; @Slf4j @RuleNode(type = ComponentType.ENRICHMENT, name = "originator attributes", + configClazz = TbGetAttributesNodeConfiguration.class, nodeDescription = "Add Message Originator Attributes or Latest Telemetry into Message Metadata", nodeDetails = "If Attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into Message metadata " + "with specific prefix: cs/shared/ss. To access those attributes in other nodes this template can be used " + diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java index ad92314324..103b4de956 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java @@ -16,14 +16,16 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import java.util.Collections; import java.util.List; /** * Created by ashvayka on 19.01.18. */ @Data -public class TbGetAttributesNodeConfiguration { +public class TbGetAttributesNodeConfiguration implements NodeConfiguration { private List clientAttributeNames; private List sharedAttributeNames; @@ -31,4 +33,13 @@ public class TbGetAttributesNodeConfiguration { private List latestTsKeyNames; + @Override + public TbGetAttributesNodeConfiguration defaultConfiguration() { + TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration(); + configuration.setClientAttributeNames(Collections.emptyList()); + configuration.setSharedAttributeNames(Collections.emptyList()); + configuration.setServerAttributeNames(Collections.emptyList()); + configuration.setLatestTsKeyNames(Collections.emptyList()); + return configuration; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index d85fb56de0..cc6d6a1197 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; @RuleNode( type = ComponentType.ENRICHMENT, name="customer attributes", + configClazz = TbGetEntityAttrNodeConfiguration.class, nodeDescription = "Add Originators Customer Attributes or Latest Telemetry into Message Metadata", nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + "To access those attributes in other nodes this template can be used " + diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java index a5e85c57d7..51951150af 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java @@ -16,13 +16,25 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import java.util.HashMap; import java.util.Map; import java.util.Optional; @Data -public class TbGetEntityAttrNodeConfiguration { +public class TbGetEntityAttrNodeConfiguration implements NodeConfiguration { private Map attrMapping; private boolean isTelemetry = false; + + @Override + public TbGetEntityAttrNodeConfiguration defaultConfiguration() { + TbGetEntityAttrNodeConfiguration configuration = new TbGetEntityAttrNodeConfiguration(); + Map attrMapping = new HashMap<>(); + attrMapping.putIfAbsent("temperature", "tempo"); + configuration.setAttrMapping(attrMapping); + configuration.setTelemetry(true); + return configuration; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java index ae0b662d48..82119926af 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java @@ -16,11 +16,28 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import java.util.HashMap; +import java.util.Map; + @Data -public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfiguration { +public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfiguration { private String relationType; private EntitySearchDirection direction; + + @Override + public TbGetRelatedAttrNodeConfiguration defaultConfiguration() { + TbGetRelatedAttrNodeConfiguration configuration = new TbGetRelatedAttrNodeConfiguration(); + Map attrMapping = new HashMap<>(); + attrMapping.putIfAbsent("temperature", "tempo"); + configuration.setAttrMapping(attrMapping); + configuration.setTelemetry(true); + configuration.setRelationType(EntityRelation.CONTAINS_TYPE); + configuration.setDirection(EntitySearchDirection.FROM); + return configuration; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index 26b756176c..22c0b9f0a8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; @RuleNode( type = ComponentType.ENRICHMENT, name="related attributes", + configClazz = TbGetRelatedAttrNodeConfiguration.class, nodeDescription = "Add Originators Related Entity Attributes or Latest Telemetry into Message Metadata", nodeDetails = "Related Entity found using configured relation direction and Relation Type. " + "If multiple Related Entities are found, only first Entity is used for attributes enrichment, other entities are discarded. " + diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index 7d9c50bfc6..b5f5e02dbe 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; @RuleNode( type = ComponentType.ENRICHMENT, name="tenant attributes", + configClazz = TbGetEntityAttrNodeConfiguration.class, nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata", nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + "To access those attributes in other nodes this template can be used " + diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java index d237df83ce..40a647a822 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java @@ -36,6 +36,7 @@ import java.util.HashSet; @RuleNode( type = ComponentType.TRANSFORMATION, name="change originator", + configClazz = TbChangeOriginatorNodeConfiguration.class, nodeDescription = "Change Message Originator To Tenant/Customer/Related Entity", nodeDetails = "Related Entity found using configured relation direction and Relation Type. " + "If multiple Related Entities are found, only first Entity is used as new Originator, other entities are discarded. ") diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeConfiguration.java index cf036810c4..3370408231 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeConfiguration.java @@ -16,12 +16,24 @@ package org.thingsboard.rule.engine.transform; import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; @Data -public class TbChangeOriginatorNodeConfiguration extends TbTransformNodeConfiguration{ +public class TbChangeOriginatorNodeConfiguration extends TbTransformNodeConfiguration implements NodeConfiguration { private String originatorSource; private EntitySearchDirection direction; private String relationType; + + @Override + public TbChangeOriginatorNodeConfiguration defaultConfiguration() { + TbChangeOriginatorNodeConfiguration configuration = new TbChangeOriginatorNodeConfiguration(); + configuration.setOriginatorSource(TbChangeOriginatorNode.CUSTOMER_SOURCE); + configuration.setDirection(EntitySearchDirection.FROM); + configuration.setRelationType(EntityRelation.CONTAINS_TYPE); + configuration.setStartNewChain(false); + return configuration; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java index babdbc3085..626790fcf8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java @@ -27,6 +27,7 @@ import javax.script.Bindings; @RuleNode( type = ComponentType.TRANSFORMATION, name = "script", + configClazz = TbTransformMsgNodeConfiguration.class, nodeDescription = "Change Message payload and Metadata using JavaScript", nodeDetails = "JavaScript function recieve 2 input parameters that can be changed inside.
" + "meta - is a Message metadata.
" + diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeConfiguration.java index 9cc926b54d..4f9e9eb681 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeConfiguration.java @@ -16,9 +16,18 @@ package org.thingsboard.rule.engine.transform; import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; @Data -public class TbTransformMsgNodeConfiguration extends TbTransformNodeConfiguration { +public class TbTransformMsgNodeConfiguration extends TbTransformNodeConfiguration implements NodeConfiguration { private String jsScript; + + @Override + public TbTransformMsgNodeConfiguration defaultConfiguration() { + TbTransformMsgNodeConfiguration configuration = new TbTransformMsgNodeConfiguration(); + configuration.setStartNewChain(false); + configuration.setJsScript("msg.passed = msg.passed * meta.temp; msg.bigObj.newProp = 'Ukraine' "); + return configuration; + } } diff --git a/ui/src/app/api/rule-chain.service.js b/ui/src/app/api/rule-chain.service.js index f17553545e..ebc48fad61 100644 --- a/ui/src/app/api/rule-chain.service.js +++ b/ui/src/app/api/rule-chain.service.js @@ -153,16 +153,21 @@ function RuleChainService($http, $q, $filter, types, componentDescriptorService) return deferred.promise; } - function getRuleNodeSupportedLinks(nodeType) { //eslint-disable-line - //TODO: - var deferred = $q.defer(); - var linkLabels = [ - { name: 'Success', custom: false }, - { name: 'Fail', custom: false }, - { name: 'Custom', custom: true }, - ]; - deferred.resolve(linkLabels); - return deferred.promise; + function getRuleNodeSupportedLinks(component) { + var relationTypes = component.configurationDescriptor.nodeDefinition.relationTypes; + var customRelations = component.configurationDescriptor.nodeDefinition.customRelations; + var linkLabels = []; + for (var i=0;i +
+
+ + + +
+
+
+
+
+
diff --git a/ui/src/app/layout/index.js b/ui/src/app/layout/index.js index e90334bf52..d397d142c8 100644 --- a/ui/src/app/layout/index.js +++ b/ui/src/app/layout/index.js @@ -29,6 +29,7 @@ import thingsboardNoAnimate from '../components/no-animate.directive'; import thingsboardOnFinishRender from '../components/finish-render.directive'; import thingsboardSideMenu from '../components/side-menu.directive'; import thingsboardDashboardAutocomplete from '../components/dashboard-autocomplete.directive'; +import thingsboardJsonObjectEdit from '../components/json-object-edit.directive'; import thingsboardUserMenu from './user-menu.directive'; @@ -90,7 +91,8 @@ export default angular.module('thingsboard.home', [ thingsboardNoAnimate, thingsboardOnFinishRender, thingsboardSideMenu, - thingsboardDashboardAutocomplete + thingsboardDashboardAutocomplete, + thingsboardJsonObjectEdit ]) .config(HomeRoutes) .controller('HomeController', HomeController) diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js index 360c8282ac..cca2a11648 100644 --- a/ui/src/app/locale/locale.constant.js +++ b/ui/src/app/locale/locale.constant.js @@ -1179,6 +1179,7 @@ export default angular.module('thingsboard.locale', []) "delete": "Delete rule node", "rulenode-details": "Rule node details", "debug-mode": "Debug mode", + "configuration": "Configuration", "link-details": "Rule node link details", "add-link": "Add link", "link-label": "Link label", diff --git a/ui/src/app/rulechain/rulechain.controller.js b/ui/src/app/rulechain/rulechain.controller.js index d9bbf2fd8d..b792f138f8 100644 --- a/ui/src/app/rulechain/rulechain.controller.js +++ b/ui/src/app/rulechain/rulechain.controller.js @@ -151,6 +151,9 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, }, 'mouseLeave': function () { destroyTooltips(); + }, + 'mouseDown': function () { + destroyTooltips(); } } }; @@ -226,16 +229,12 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, edgeDoubleClick: function (event, edge) { var sourceNode = vm.modelservice.nodes.getNodeByConnectorId(edge.source); if (sourceNode.component.type != types.ruleNodeType.INPUT.value) { - ruleChainService.getRuleNodeSupportedLinks(sourceNode.component.clazz).then( - (labels) => { - vm.isEditingRuleNode = false; - vm.editingRuleNode = null; - vm.editingRuleNodeLinkLabels = labels; - vm.isEditingRuleNodeLink = true; - vm.editingRuleNodeLinkIndex = vm.ruleChainModel.edges.indexOf(edge); - vm.editingRuleNodeLink = angular.copy(edge); - } - ); + vm.isEditingRuleNode = false; + vm.editingRuleNode = null; + vm.editingRuleNodeLinkLabels = ruleChainService.getRuleNodeSupportedLinks(sourceNode.component); + vm.isEditingRuleNodeLink = true; + vm.editingRuleNodeLinkIndex = vm.ruleChainModel.edges.indexOf(edge); + vm.editingRuleNodeLink = angular.copy(edge); } }, nodeCallbacks: { @@ -267,16 +266,10 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, deferred.resolve(edge); } } else { - ruleChainService.getRuleNodeSupportedLinks(sourceNode.component.clazz).then( - (labels) => { - addRuleNodeLink(event, edge, labels).then( - (link) => { - deferred.resolve(link); - }, - () => { - deferred.reject(); - } - ); + var labels = ruleChainService.getRuleNodeSupportedLinks(sourceNode.component); + addRuleNodeLink(event, edge, labels).then( + (link) => { + deferred.resolve(link); }, () => { deferred.reject(); @@ -309,24 +302,19 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, y: 10+50*model.nodes.length, connectors: [] }; - if (componentType == types.ruleNodeType.RULE_CHAIN.value) { + if (ruleNodeComponent.configurationDescriptor.nodeDefinition.inEnabled) { node.connectors.push( { type: flowchartConstants.leftConnectorType, - id: model.nodes.length - } - ); - } else { - node.connectors.push( - { - type: flowchartConstants.leftConnectorType, - id: model.nodes.length*2 + id: model.nodes.length * 2 } ); + } + if (ruleNodeComponent.configurationDescriptor.nodeDefinition.outEnabled) { node.connectors.push( { type: flowchartConstants.rightConnectorType, - id: model.nodes.length*2+1 + id: model.nodes.length * 2 + 1 } ); } @@ -398,17 +386,24 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, name: ruleNode.name, nodeClass: vm.types.ruleNodeType[component.type].nodeClass, icon: vm.types.ruleNodeType[component.type].icon, - connectors: [ + connectors: [] + }; + if (component.configurationDescriptor.nodeDefinition.inEnabled) { + node.connectors.push( { type: flowchartConstants.leftConnectorType, id: vm.nextConnectorID++ - }, + } + ); + } + if (component.configurationDescriptor.nodeDefinition.outEnabled) { + node.connectors.push( { type: flowchartConstants.rightConnectorType, id: vm.nextConnectorID++ } - ] - }; + ); + } nodes.push(node); vm.ruleChainModel.nodes.push(node); } @@ -590,6 +585,9 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, } function addRuleNode($event, ruleNode) { + + ruleNode.configuration = angular.copy(ruleNode.component.configurationDescriptor.nodeDefinition.defaultConfiguration); + $mdDialog.show({ controller: 'AddRuleNodeController', controllerAs: 'vm', @@ -601,13 +599,15 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, }).then(function (ruleNode) { ruleNode.id = vm.nextNodeID++; ruleNode.connectors = []; - ruleNode.connectors.push( - { - id: vm.nextConnectorID++, - type: flowchartConstants.leftConnectorType - } - ); - if (ruleNode.component.type != types.ruleNodeType.RULE_CHAIN.value) { + if (ruleNode.component.configurationDescriptor.nodeDefinition.inEnabled) { + ruleNode.connectors.push( + { + id: vm.nextConnectorID++, + type: flowchartConstants.leftConnectorType + } + ); + } + if (ruleNode.component.configurationDescriptor.nodeDefinition.outEnabled) { ruleNode.connectors.push( { id: vm.nextConnectorID++, diff --git a/ui/src/app/rulechain/rulenode-fieldset.tpl.html b/ui/src/app/rulechain/rulenode-fieldset.tpl.html index 0d16e45405..30cf0752cd 100644 --- a/ui/src/app/rulechain/rulenode-fieldset.tpl.html +++ b/ui/src/app/rulechain/rulenode-fieldset.tpl.html @@ -38,6 +38,11 @@ ng-model="ruleNode.debugMode">{{ 'rulenode.debug-mode' | translate }} + + diff --git a/ui/src/app/rulechain/rulenode.directive.js b/ui/src/app/rulechain/rulenode.directive.js index 998e9981c6..be3e9c36b5 100644 --- a/ui/src/app/rulechain/rulenode.directive.js +++ b/ui/src/app/rulechain/rulenode.directive.js @@ -14,6 +14,8 @@ * limitations under the License. */ +import './rulenode.scss'; + /* eslint-disable import/no-unresolved, import/default */ import ruleNodeFieldsetTemplate from './rulenode-fieldset.tpl.html'; diff --git a/ui/src/app/rulechain/rulenode.scss b/ui/src/app/rulechain/rulenode.scss new file mode 100644 index 0000000000..febc637a37 --- /dev/null +++ b/ui/src/app/rulechain/rulenode.scss @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2018 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.tb-rulenode { + tb-json-object-edit.tb-rule-node-configuration-json { + height: 300px; + display: block; + } +} \ No newline at end of file diff --git a/ui/src/app/rulechain/rulenode.tpl.html b/ui/src/app/rulechain/rulenode.tpl.html index 5a521a8333..ffc8a0f20d 100644 --- a/ui/src/app/rulechain/rulenode.tpl.html +++ b/ui/src/app/rulechain/rulenode.tpl.html @@ -19,7 +19,7 @@ id="{{node.id}}" ng-attr-style="position: absolute; top: {{ node.y }}px; left: {{ node.x }}px;" ng-dblclick="callbacks.doubleClick($event, node)" - ng-mouseover="callbacks.mouseOver($event, node)" + ng-mousedown="callbacks.mouseDown($event, node)" ng-mouseenter="callbacks.mouseEnter($event, node)" ng-mouseleave="callbacks.mouseLeave($event, node)">
diff --git a/ui/src/scss/main.scss b/ui/src/scss/main.scss index 93ff3205c0..6aa662c58c 100644 --- a/ui/src/scss/main.scss +++ b/ui/src/scss/main.scss @@ -203,6 +203,12 @@ md-sidenav { * THINGSBOARD SPECIFIC ***********************/ +$swift-ease-out-duration: 0.4s !default; +$swift-ease-out-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default; + +$input-label-float-offset: 6px !default; +$input-label-float-scale: 0.75 !default; + label { &.tb-title { pointer-events: none; @@ -213,6 +219,18 @@ label { &.no-padding { padding-bottom: 0px; } + &.tb-required:after { + content: ' *'; + font-size: 13px; + vertical-align: top; + color: rgba(0,0,0,0.54); + } + &.tb-error { + color: rgb(221,44,0); + &.tb-required:after { + color: rgb(221,44,0); + } + } } }