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 c684b200c5..eb8941cc8c 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 @@ -35,7 +35,7 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback; nodeDetails = "Evaluate incoming Message with configured JS condition. " + "If True - send Message via True chain, otherwise False chain is used." + "Message payload can be accessed via msg property. For example msg.temperature < 10;" + - "Message metadata can be accessed via meta property. For example meta.customerName === 'John';", + "Message metadata can be accessed via metadata property. For example metadata.customerName === 'John';", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeScriptConfig") @@ -47,7 +47,7 @@ public class TbJsFilterNode implements TbNode { @Override public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbJsFilterNodeConfiguration.class); - this.jsEngine = new NashornJsEngine(config.getJsScript()); + this.jsEngine = new NashornJsEngine(config.getJsScript(), "Filter"); } @Override 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 3b19c7c641..2d776ce3e3 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 @@ -26,7 +26,7 @@ public class TbJsFilterNodeConfiguration implements NodeConfiguration { @Override public TbJsFilterNodeConfiguration defaultConfiguration() { TbJsFilterNodeConfiguration configuration = new TbJsFilterNodeConfiguration(); - configuration.setJsScript("msg.passed < 15 && msg.name === 'Vit' && meta.temp == 10 && msg.bigObj.prop == 42;"); + configuration.setJsScript("return msg.passed < 15 && msg.name === 'Vit' && metadata.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 c1236a4653..98f0ebcd76 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 @@ -36,7 +36,9 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback; 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. " + "Message payload can be accessed via msg property. For example msg.temperature < 10; " + - "Message metadata can be accessed via meta property. For example meta.customerName === 'John';") + "Message metadata can be accessed via metadata property. For example metadata.customerName === 'John';", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbFilterNodeSwitchConfig") public class TbJsSwitchNode implements TbNode { private TbJsSwitchNodeConfiguration config; @@ -45,22 +47,11 @@ public class TbJsSwitchNode implements TbNode { @Override public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbJsSwitchNodeConfiguration.class); - if (config.getAllowedRelations().size() < 1) { - String message = "Switch node should have at least 1 relation"; - log.error(message); - throw new IllegalStateException(message); - } - if (!config.isRouteToAllWithNoCheck()) { - this.jsEngine = new NashornJsEngine(config.getJsScript()); - } + this.jsEngine = new NashornJsEngine(config.getJsScript(), "Switch"); } @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (config.isRouteToAllWithNoCheck()) { - ctx.tellNext(msg, config.getAllowedRelations()); - return; - } ListeningExecutor jsExecutor = ctx.getJsExecutor(); withCallback(jsExecutor.executeAsync(() -> jsEngine.executeSwitch(toBindings(msg))), result -> processSwitch(ctx, msg, result), @@ -68,15 +59,7 @@ public class TbJsSwitchNode implements TbNode { } private void processSwitch(TbContext ctx, TbMsg msg, Set nextRelations) { - if (validateRelations(nextRelations)) { - ctx.tellNext(msg, nextRelations); - } else { - ctx.tellError(msg, new IllegalStateException("Unsupported relation for switch " + nextRelations)); - } - } - - private boolean validateRelations(Set nextRelations) { - return config.getAllowedRelations().containsAll(nextRelations); + ctx.tellNext(msg, nextRelations); } private Bindings toBindings(TbMsg msg) { 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 b354c7199f..3a4856cd93 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 @@ -25,19 +25,15 @@ import java.util.Set; 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" + + configuration.setJsScript("function nextRelation(metadata, msg) {\n" + " return ['one','nine'];" + "};\n" + "\n" + - "nextRelation(meta, msg);"); - configuration.setAllowedRelations(Sets.newHashSet("one", "two")); - configuration.setRouteToAllWithNoCheck(false); + "return nextRelation(metadata, msg);"); 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 3a86c25afb..8d72a7b711 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 @@ -31,7 +31,9 @@ import org.thingsboard.server.common.msg.TbMsg; 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.") + "If incoming MessageType is expected - send Message via Success chain, otherwise Failure chain is used.", + uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + configDirective = "tbFilterNodeMessageTypeConfig") public class TbMsgTypeFilterNode implements TbNode { TbMsgTypeFilterNodeConfiguration config; 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 a2e1b179f0..aafd2ed7c2 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 @@ -33,7 +33,7 @@ public class TbMsgTypeFilterNodeConfiguration implements NodeConfiguration { @Override public TbMsgTypeFilterNodeConfiguration defaultConfiguration() { TbMsgTypeFilterNodeConfiguration configuration = new TbMsgTypeFilterNodeConfiguration(); - configuration.setMessageTypes(Arrays.asList("GET_ATTRIBUTES","POST_ATTRIBUTES","POST_TELEMETRY","RPC_REQUEST")); + configuration.setMessageTypes(Arrays.asList("POST_ATTRIBUTES","POST_TELEMETRY","RPC_REQUEST")); return configuration; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/js/NashornJsEngine.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/js/NashornJsEngine.java index 082535f0fe..a4add405e7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/js/NashornJsEngine.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/js/NashornJsEngine.java @@ -34,14 +34,20 @@ import java.util.Set; @Slf4j public class NashornJsEngine { - public static final String METADATA = "meta"; + public static final String METADATA = "metadata"; public static final String DATA = "msg"; + + private static final String JS_WRAPPER_PREFIX_TEMPLATE = "function %s(msg, metadata) { "; + private static final String JS_WRAPPER_SUFFIX_TEMPLATE = "}\n %s(msg, metadata);"; + private static NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); private CompiledScript engine; - public NashornJsEngine(String script) { - engine = compileScript(script); + public NashornJsEngine(String script, String functionName) { + String jsWrapperPrefix = String.format(JS_WRAPPER_PREFIX_TEMPLATE, functionName); + String jsWrapperSuffix = String.format(JS_WRAPPER_SUFFIX_TEMPLATE, functionName); + engine = compileScript(jsWrapperPrefix + script + jsWrapperSuffix); } private static CompiledScript compileScript(String script) { @@ -58,15 +64,15 @@ public class NashornJsEngine { public static Bindings bindMsg(TbMsg msg) { try { Bindings bindings = new SimpleBindings(); - bindings.put(METADATA, msg.getMetaData().getData()); - if (ArrayUtils.isNotEmpty(msg.getData())) { ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(msg.getData()); Map map = mapper.treeToValue(jsonNode, Map.class); bindings.put(DATA, map); + } else { + bindings.put(DATA, Collections.emptyMap()); } - + bindings.put(METADATA, msg.getMetaData().getData()); return bindings; } catch (Throwable th) { throw new IllegalArgumentException("Cannot bind js args", th); 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 69ee9d7c79..4fc0f3e48f 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 @@ -42,7 +42,7 @@ import static org.thingsboard.server.common.data.DataConstants.*; 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 " + - "meta.cs.temperature or meta.shared.limit " + + "metadata.cs.temperature or metadata.shared.limit " + "If Latest Telemetry enrichment configured, latest telemetry added into metadata without prefix.") public class TbGetAttributesNode implements TbNode { 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 cc6d6a1197..c59a65e27d 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 @@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; 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 " + - "meta.temperature. If Latest Telemetry enrichment configured, latest telemetry added into metadata") + "metadata.temperature. If Latest Telemetry enrichment configured, latest telemetry added into metadata") public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode { @Override 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 22c0b9f0a8..4cd5cd5ba6 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 @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; "If multiple Related Entities are found, only first Entity is used for attributes enrichment, other entities are discarded. " + "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + "To access those attributes in other nodes this template can be used " + - "meta.temperature. If Latest Telemetry enrichment configured, latest telemetry added into metadata") + "metadata.temperature. If Latest Telemetry enrichment configured, latest telemetry added into metadata") public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode { private TbGetRelatedAttrNodeConfiguration config; 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 b5f5e02dbe..3165385587 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 @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; 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 " + - "meta.temperature. If Latest Telemetry enrichment configured, latest telemetry added into metadata") + "metadata.temperature. If Latest Telemetry enrichment configured, latest telemetry added into metadata") public class TbGetTenantAttributeNode extends TbEntityGetAttrNode { @Override 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 626790fcf8..e47ea0f8db 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 @@ -30,7 +30,7 @@ import javax.script.Bindings; 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.
" + + "metadata - is a Message metadata.
" + "msg - is a Message payload.
Any properties can be changed/removed/added in those objects.") public class TbTransformMsgNode extends TbAbstractTransformNode { @@ -40,7 +40,7 @@ public class TbTransformMsgNode extends TbAbstractTransformNode { @Override public void init(TbNodeConfiguration configuration, TbNodeState state) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbTransformMsgNodeConfiguration.class); - this.jsEngine = new NashornJsEngine(config.getJsScript()); + this.jsEngine = new NashornJsEngine(config.getJsScript(), "Transform"); setConfig(config); } 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 4f9e9eb681..09d5ac43ad 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 @@ -27,7 +27,7 @@ public class TbTransformMsgNodeConfiguration extends TbTransformNodeConfiguratio public TbTransformMsgNodeConfiguration defaultConfiguration() { TbTransformMsgNodeConfiguration configuration = new TbTransformMsgNodeConfiguration(); configuration.setStartNewChain(false); - configuration.setJsScript("msg.passed = msg.passed * meta.temp; msg.bigObj.newProp = 'Ukraine' "); + configuration.setJsScript("return msg.passed = msg.passed * metadata.temp; msg.bigObj.newProp = 'Ukraine' "); return configuration; } } diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.css b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.css new file mode 100644 index 0000000000..a6103c1d56 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.css @@ -0,0 +1,2 @@ +.tb-message-type-autocomplete .tb-not-found{display:block;line-height:1.5;height:48px}.tb-message-type-autocomplete .tb-not-found .tb-no-entries{line-height:48px}.tb-message-type-autocomplete li{height:auto!important;white-space:normal!important} +/*# sourceMappingURL=rulenode-core-config.css.map*/ \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index f254cf599d..3fe859d90f 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1,2 +1,2 @@ -!function(e){function t(r){if(n[r])return n[r].exports;var u=n[r]={exports:{},id:r,loaded:!1};return e[r].call(u.exports,u,u.exports,t),u.loaded=!0,u.exports}var n={};return t.m=e,t.c=n,t.p="/static/",t(0)}([function(e,t,n){e.exports=n(3)},function(e,t){e.exports='
'},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function u(e){var t=function(t,n,r,u){var o=i.default;n.html(o),t.$watch("configuration",function(e,n){angular.equals(e,n)||u.$setViewValue(t.configuration)}),u.$render=function(){t.configuration=u.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}u.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=u;var o=n(1),i=r(o)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var u=n(2),o=r(u),i=n(5),a=r(i);t.default=angular.module("thingsboard.ruleChain.config",[]).directive("tbFilterNodeScriptConfig",o.default).config(a.default).name},function(e,t){"use strict";function n(e){var t={tb:{rulenode:{filter:"Filter"}}};angular.merge(e.en_US,t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function u(e,t){(0,i.default)(t);for(var n in t){var r=t[n];e.translations(n,r)}}u.$inject=["$translateProvider","locales"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=u;var o=n(4),i=r(o)}]); +!function(e){function t(s){if(a[s])return a[s].exports;var n=a[s]={exports:{},id:s,loaded:!1};return e[s].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var a={};return t.m=e,t.c=a,t.p="/static/",t(0)}([function(e,t,a){e.exports=a(8)},function(e,t){},function(e,t){e.exports='
{{item}}
tb.rulenode.no-message-types-found
tb.rulenode.no-message-type-matching tb.rulenode.create-new-message-type
{{$chip.name}}
'},function(e,t){e.exports="
"},function(e,t){e.exports="
"},function(e,t,a){"use strict";function s(e){return e&&e.__esModule?e:{default:e}}function n(e,t,a){var s=function(s,n,r,l){function u(){if(l.$viewValue){for(var e=[],t=0;t 15;"); + initWithScript("return 10 > 15;"); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, new TbMsgMetaData(), "{}".getBytes()); mockJsExecutor(); @@ -64,7 +64,7 @@ public class TbJsFilterNodeTest { @Test public void notValidMsgDataThrowsException() throws TbNodeException { - initWithScript("10 > 15;"); + initWithScript("return 10 > 15;"); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, new TbMsgMetaData(), new byte[4]); when(ctx.getJsExecutor()).thenReturn(executor); @@ -77,7 +77,7 @@ public class TbJsFilterNodeTest { @Test public void exceptionInJsThrowsException() throws TbNodeException { - initWithScript("meta.temp.curr < 15;"); + initWithScript("return metadata.temp.curr < 15;"); TbMsgMetaData metaData = new TbMsgMetaData(); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{}".getBytes()); mockJsExecutor(); @@ -89,12 +89,12 @@ public class TbJsFilterNodeTest { @Test(expected = IllegalArgumentException.class) public void notValidScriptThrowsException() throws TbNodeException { - initWithScript("10 > 15 asdq out"); + initWithScript("return 10 > 15 asdq out"); } @Test public void metadataConditionCanBeFalse() throws TbNodeException { - initWithScript("meta.humidity < 15;"); + initWithScript("return metadata.humidity < 15;"); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temp", "10"); metaData.putValue("humidity", "99"); @@ -109,7 +109,7 @@ public class TbJsFilterNodeTest { @Test public void metadataConditionCanBeTrue() throws TbNodeException { - initWithScript("meta.temp < 15;"); + initWithScript("return metadata.temp < 15;"); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temp", "10"); metaData.putValue("humidity", "99"); @@ -123,7 +123,7 @@ public class TbJsFilterNodeTest { @Test public void msgJsonParsedAndBinded() throws TbNodeException { - initWithScript("msg.passed < 15 && msg.name === 'Vit' && meta.temp == 10 && msg.bigObj.prop == 42;"); + initWithScript("return msg.passed < 15 && msg.name === 'Vit' && metadata.temp == 10 && msg.bigObj.prop == 42;"); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temp", "10"); metaData.putValue("humidity", "99"); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java index e70d4e16f4..01227f48aa 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java @@ -52,28 +52,17 @@ public class TbJsSwitchNodeTest { @Mock private ListeningExecutor executor; - @Test - public void routeToAllDoNotEvaluatesJs() throws TbNodeException { - HashSet relations = Sets.newHashSet("one", "two"); - initWithScript("test qwerty", relations, true); - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, new TbMsgMetaData(), "{}".getBytes()); - - node.onMsg(ctx, msg); - verify(ctx).tellNext(msg, relations); - verifyNoMoreInteractions(ctx, executor); - } - @Test public void multipleRoutesAreAllowed() throws TbNodeException { - String jsCode = "function nextRelation(meta, msg) {\n" + - " if(msg.passed == 5 && meta.temp == 10)\n" + + String jsCode = "function nextRelation(metadata, msg) {\n" + + " if(msg.passed == 5 && metadata.temp == 10)\n" + " return ['three', 'one']\n" + " else\n" + " return 'two';\n" + "};\n" + "\n" + - "nextRelation(meta, msg);"; - initWithScript(jsCode, Sets.newHashSet("one", "two", "three"), false); + "return nextRelation(metadata, msg);"; + initWithScript(jsCode); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temp", "10"); metaData.putValue("humidity", "99"); @@ -89,15 +78,15 @@ public class TbJsSwitchNodeTest { @Test public void allowedRelationPassed() throws TbNodeException { - String jsCode = "function nextRelation(meta, msg) {\n" + - " if(msg.passed == 5 && meta.temp == 10)\n" + + String jsCode = "function nextRelation(metadata, msg) {\n" + + " if(msg.passed == 5 && metadata.temp == 10)\n" + " return 'one'\n" + " else\n" + " return 'two';\n" + "};\n" + "\n" + - "nextRelation(meta, msg);"; - initWithScript(jsCode, Sets.newHashSet("one", "two"), false); + "return nextRelation(metadata, msg);"; + initWithScript(jsCode); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temp", "10"); metaData.putValue("humidity", "99"); @@ -111,32 +100,9 @@ public class TbJsSwitchNodeTest { verify(ctx).tellNext(msg, Sets.newHashSet("one")); } - @Test - public void unknownRelationThrowsException() throws TbNodeException { - String jsCode = "function nextRelation(meta, msg) {\n" + - " return ['one','nine'];" + - "};\n" + - "\n" + - "nextRelation(meta, msg);"; - initWithScript(jsCode, Sets.newHashSet("one", "two"), false); - TbMsgMetaData metaData = new TbMsgMetaData(); - metaData.putValue("temp", "10"); - metaData.putValue("humidity", "99"); - String rawJson = "{\"name\": \"Vit\", \"passed\": 5}"; - - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson.getBytes()); - mockJsExecutor(); - - node.onMsg(ctx, msg); - verify(ctx).getJsExecutor(); - verifyError(msg, "Unsupported relation for switch [nine, one]", IllegalStateException.class); - } - - private void initWithScript(String script, Set relations, boolean routeToAll) throws TbNodeException { + private void initWithScript(String script) throws TbNodeException { TbJsSwitchNodeConfiguration config = new TbJsSwitchNodeConfiguration(); config.setJsScript(script); - config.setAllowedRelations(relations); - config.setRouteToAllWithNoCheck(routeToAll); ObjectMapper mapper = new ObjectMapper(); TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java index d69bad8864..c6b3441f27 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java @@ -51,7 +51,7 @@ public class TbTransformMsgNodeTest { @Test public void metadataCanBeUpdated() throws TbNodeException { - initWithScript("meta.temp = meta.temp * 10;"); + initWithScript("return metadata.temp = metadata.temp * 10;"); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temp", "7"); metaData.putValue("humidity", "99"); @@ -70,7 +70,7 @@ public class TbTransformMsgNodeTest { @Test public void metadataCanBeAdded() throws TbNodeException { - initWithScript("meta.newAttr = meta.humidity - msg.passed;"); + initWithScript("return metadata.newAttr = metadata.humidity - msg.passed;"); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temp", "7"); metaData.putValue("humidity", "99"); @@ -89,7 +89,7 @@ public class TbTransformMsgNodeTest { @Test public void payloadCanBeUpdated() throws TbNodeException { - initWithScript("msg.passed = msg.passed * meta.temp; msg.bigObj.newProp = 'Ukraine' "); + initWithScript("return msg.passed = msg.passed * metadata.temp; msg.bigObj.newProp = 'Ukraine' "); TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("temp", "7"); metaData.putValue("humidity", "99"); diff --git a/ui/server.js b/ui/server.js index 0513600afd..65a2bc7f45 100644 --- a/ui/server.js +++ b/ui/server.js @@ -32,7 +32,6 @@ const forwardPort = 8080; const ruleNodeUiforwardHost = 'localhost'; const ruleNodeUiforwardPort = 8080; -//const ruleNodeUiforwardPort = 5000; const app = express(); const server = http.createServer(app); diff --git a/ui/src/app/components/json-object-edit.directive.js b/ui/src/app/components/json-object-edit.directive.js index db0aa60bb5..215b7b9fe8 100644 --- a/ui/src/app/components/json-object-edit.directive.js +++ b/ui/src/app/components/json-object-edit.directive.js @@ -84,17 +84,32 @@ function JsonObjectEdit($compile, $templateCache, $document, toast, utils) { scope.$watch('contentBody', function (newVal, prevVal) { if (!angular.equals(newVal, prevVal)) { var object = scope.validate(); - ngModelCtrl.$setViewValue(object); + if (scope.objectValid) { + if (object == null) { + scope.object = null; + } else { + if (scope.object == null) { + scope.object = {}; + } + Object.keys(scope.object).forEach(function (key) { + delete scope.object[key]; + }); + Object.keys(object).forEach(function (key) { + scope.object[key] = object[key]; + }); + } + ngModelCtrl.$setViewValue(scope.object); + } scope.updateValidity(); } }); ngModelCtrl.$render = function () { - var object = ngModelCtrl.$viewValue; + scope.object = ngModelCtrl.$viewValue; var content = ''; try { - if (object) { - content = angular.toJson(object, true); + if (scope.object) { + content = angular.toJson(scope.object, true); } } catch (e) { // diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js index b511b56c33..a70ca14c5f 100644 --- a/ui/src/app/locale/locale.constant.js +++ b/ui/src/app/locale/locale.constant.js @@ -1171,6 +1171,7 @@ export default angular.module('thingsboard.locale', []) "debug-mode": "Debug mode" }, "rulenode": { + "details": "Details", "add": "Add rule node", "name": "Name", "name-required": "Name is required.", diff --git a/ui/src/app/rulechain/rulechain.controller.js b/ui/src/app/rulechain/rulechain.controller.js index dd48bb007a..fbdda227fb 100644 --- a/ui/src/app/rulechain/rulechain.controller.js +++ b/ui/src/app/rulechain/rulechain.controller.js @@ -256,6 +256,9 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, vm.isEditingRuleNodeLink = true; vm.editingRuleNodeLinkIndex = vm.ruleChainModel.edges.indexOf(edge); vm.editingRuleNodeLink = angular.copy(edge); + $mdUtil.nextTick(() => { + vm.ruleNodeLinkForm.$setPristine(); + }); } }, nodeCallbacks: { @@ -266,6 +269,9 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, vm.isEditingRuleNode = true; vm.editingRuleNodeIndex = vm.ruleChainModel.nodes.indexOf(node); vm.editingRuleNode = angular.copy(node); + $mdUtil.nextTick(() => { + vm.ruleNodeForm.$setPristine(); + }); } } }, diff --git a/ui/src/app/rulechain/rulechain.tpl.html b/ui/src/app/rulechain/rulechain.tpl.html index d23f920e0f..3083f83835 100644 --- a/ui/src/app/rulechain/rulechain.tpl.html +++ b/ui/src/app/rulechain/rulechain.tpl.html @@ -65,7 +65,8 @@
-
- - -
+ + +
+ + +
+
+
{ + if (scope.nodeDefinition) { + validateDefinedDirective(); + } + }); function validateDefinedDirective() { if (scope.nodeDefinition.uiResourceLoadError && scope.nodeDefinition.uiResourceLoadError.length) { diff --git a/ui/src/app/rulechain/rulenode-defined-config.directive.js b/ui/src/app/rulechain/rulenode-defined-config.directive.js index 5ec2620aaf..5100fbb96b 100644 --- a/ui/src/app/rulechain/rulenode-defined-config.directive.js +++ b/ui/src/app/rulechain/rulenode-defined-config.directive.js @@ -36,10 +36,14 @@ export default function RuleNodeDefinedConfigDirective($compile) { }; function loadTemplate() { + if (scope.ruleNodeConfigScope) { + scope.ruleNodeConfigScope.$destroy(); + } var directive = snake_case(attrs.ruleNodeDirective, '-'); var template = `<${directive} ng-model="configuration" ng-required="required" ng-readonly="readonly">`; element.html(template); - $compile(element.contents())(scope); + scope.ruleNodeConfigScope = scope.$new(); + $compile(element.contents())(scope.ruleNodeConfigScope); } function snake_case(name, separator) { diff --git a/ui/src/app/rulechain/rulenode-fieldset.tpl.html b/ui/src/app/rulechain/rulenode-fieldset.tpl.html index ad109ef6cb..7b0fae5a5f 100644 --- a/ui/src/app/rulechain/rulenode-fieldset.tpl.html +++ b/ui/src/app/rulechain/rulenode-fieldset.tpl.html @@ -21,33 +21,26 @@
- - - -
- - - -
-
rulenode.name-required
-
-
- - {{ 'rulenode.debug-mode' | translate }} - - +
+ + + +
+
rulenode.name-required
+
+
+ + {{ 'rulenode.debug-mode' | translate }} + + +
-