Rule Node Configuration
This commit is contained in:
parent
73473e3beb
commit
adb71ecfe7
@ -180,7 +180,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
|
|||||||
return scannedComponent;
|
return scannedComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NodeDefinition prepareNodeDefinition(RuleNode nodeAnnotation) throws IOException {
|
private NodeDefinition prepareNodeDefinition(RuleNode nodeAnnotation) throws Exception {
|
||||||
NodeDefinition nodeDefinition = new NodeDefinition();
|
NodeDefinition nodeDefinition = new NodeDefinition();
|
||||||
nodeDefinition.setDetails(nodeAnnotation.nodeDetails());
|
nodeDefinition.setDetails(nodeAnnotation.nodeDetails());
|
||||||
nodeDefinition.setDescription(nodeAnnotation.nodeDescription());
|
nodeDefinition.setDescription(nodeAnnotation.nodeDescription());
|
||||||
@ -188,9 +188,10 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
|
|||||||
nodeDefinition.setOutEnabled(nodeAnnotation.outEnabled());
|
nodeDefinition.setOutEnabled(nodeAnnotation.outEnabled());
|
||||||
nodeDefinition.setRelationTypes(nodeAnnotation.relationTypes());
|
nodeDefinition.setRelationTypes(nodeAnnotation.relationTypes());
|
||||||
nodeDefinition.setCustomRelations(nodeAnnotation.customRelations());
|
nodeDefinition.setCustomRelations(nodeAnnotation.customRelations());
|
||||||
String defaultConfigResourceName = nodeAnnotation.defaultConfigResource();
|
Class<? extends NodeConfiguration> configClazz = nodeAnnotation.configClazz();
|
||||||
nodeDefinition.setDefaultConfiguration(mapper.readTree(
|
NodeConfiguration config = configClazz.newInstance();
|
||||||
Resources.toString(Resources.getResource(defaultConfigResourceName), Charsets.UTF_8)));
|
NodeConfiguration defaultConfiguration = config.defaultConfiguration();
|
||||||
|
nodeDefinition.setDefaultConfiguration(mapper.valueToTree(defaultConfiguration));
|
||||||
return nodeDefinition;
|
return nodeDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -234,7 +234,7 @@ caffeine:
|
|||||||
specs:
|
specs:
|
||||||
relations:
|
relations:
|
||||||
timeToLiveInMinutes: 1440
|
timeToLiveInMinutes: 1440
|
||||||
maxSize: 100000
|
maxSize: 0
|
||||||
deviceCredentials:
|
deviceCredentials:
|
||||||
timeToLiveInMinutes: 1440
|
timeToLiveInMinutes: 1440
|
||||||
maxSize: 100000
|
maxSize: 100000
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
@ -35,15 +35,16 @@ public @interface RuleNode {
|
|||||||
|
|
||||||
String nodeDetails();
|
String nodeDetails();
|
||||||
|
|
||||||
|
Class<? extends NodeConfiguration> configClazz();
|
||||||
|
|
||||||
boolean inEnabled() default true;
|
boolean inEnabled() default true;
|
||||||
|
|
||||||
boolean outEnabled() default true;
|
boolean outEnabled() default true;
|
||||||
|
|
||||||
ComponentScope scope() default ComponentScope.TENANT;
|
ComponentScope scope() default ComponentScope.TENANT;
|
||||||
|
|
||||||
String defaultConfigResource() default "EmptyNodeConfig.json";
|
|
||||||
|
|
||||||
String[] relationTypes() default {"Success", "Failure"};
|
String[] relationTypes() default {"Success", "Failure"};
|
||||||
|
|
||||||
boolean customRelations() default false;
|
boolean customRelations() default false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
{
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
{
|
|
||||||
}
|
|
||||||
@ -30,6 +30,7 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
|||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.FILTER,
|
type = ComponentType.FILTER,
|
||||||
name = "script", relationTypes = {"True", "False", "Failure"},
|
name = "script", relationTypes = {"True", "False", "Failure"},
|
||||||
|
configClazz = TbJsFilterNodeConfiguration.class,
|
||||||
nodeDescription = "Filter incoming messages using JS script",
|
nodeDescription = "Filter incoming messages using JS script",
|
||||||
nodeDetails = "Evaluate incoming Message with configured JS condition. " +
|
nodeDetails = "Evaluate incoming Message with configured JS condition. " +
|
||||||
"If <b>True</b> - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used." +
|
"If <b>True</b> - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used." +
|
||||||
|
|||||||
@ -16,9 +16,17 @@
|
|||||||
package org.thingsboard.rule.engine.filter;
|
package org.thingsboard.rule.engine.filter;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TbJsFilterNodeConfiguration {
|
public class TbJsFilterNodeConfiguration implements NodeConfiguration {
|
||||||
|
|
||||||
private String jsScript;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
|||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.FILTER,
|
type = ComponentType.FILTER,
|
||||||
name = "switch", customRelations = true,
|
name = "switch", customRelations = true,
|
||||||
|
configClazz = TbJsSwitchNodeConfiguration.class,
|
||||||
nodeDescription = "Route incoming Message to one or multiple output chains",
|
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. " +
|
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. " +
|
"If Array is empty - message not routed to next Node. " +
|
||||||
|
|||||||
@ -15,14 +15,29 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.rule.engine.filter;
|
package org.thingsboard.rule.engine.filter;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TbJsSwitchNodeConfiguration {
|
public class TbJsSwitchNodeConfiguration implements NodeConfiguration {
|
||||||
|
|
||||||
private String jsScript;
|
private String jsScript;
|
||||||
private Set<String> allowedRelations;
|
private Set<String> allowedRelations;
|
||||||
private boolean routeToAllWithNoCheck;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import org.thingsboard.server.common.msg.TbMsg;
|
|||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.FILTER,
|
type = ComponentType.FILTER,
|
||||||
name = "message type",
|
name = "message type",
|
||||||
|
configClazz = TbMsgTypeFilterNodeConfiguration.class,
|
||||||
nodeDescription = "Filter incoming messages by Message Type",
|
nodeDescription = "Filter incoming messages by Message Type",
|
||||||
nodeDetails = "Evaluate incoming Message with configured JS condition. " +
|
nodeDetails = "Evaluate incoming Message with configured JS condition. " +
|
||||||
"If incoming MessageType is expected - send Message via <b>Success</b> chain, otherwise <b>Failure</b> chain is used.")
|
"If incoming MessageType is expected - send Message via <b>Success</b> chain, otherwise <b>Failure</b> chain is used.")
|
||||||
|
|||||||
@ -16,15 +16,24 @@
|
|||||||
package org.thingsboard.rule.engine.filter;
|
package org.thingsboard.rule.engine.filter;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by ashvayka on 19.01.18.
|
* Created by ashvayka on 19.01.18.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class TbMsgTypeFilterNodeConfiguration {
|
public class TbMsgTypeFilterNodeConfiguration implements NodeConfiguration {
|
||||||
|
|
||||||
private List<String> messageTypes;
|
private List<String> messageTypes;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbMsgTypeFilterNodeConfiguration defaultConfiguration() {
|
||||||
|
TbMsgTypeFilterNodeConfiguration configuration = new TbMsgTypeFilterNodeConfiguration();
|
||||||
|
configuration.setMessageTypes(Arrays.asList("GET_ATTRIBUTES","POST_ATTRIBUTES","POST_TELEMETRY","RPC_REQUEST"));
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@ import static org.thingsboard.server.common.data.DataConstants.*;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@RuleNode(type = ComponentType.ENRICHMENT,
|
@RuleNode(type = ComponentType.ENRICHMENT,
|
||||||
name = "originator attributes",
|
name = "originator attributes",
|
||||||
|
configClazz = TbGetAttributesNodeConfiguration.class,
|
||||||
nodeDescription = "Add Message Originator Attributes or Latest Telemetry into Message Metadata",
|
nodeDescription = "Add Message Originator Attributes or Latest Telemetry into Message Metadata",
|
||||||
nodeDetails = "If Attributes enrichment configured, <b>CLIENT/SHARED/SERVER</b> attributes are added into Message metadata " +
|
nodeDetails = "If Attributes enrichment configured, <b>CLIENT/SHARED/SERVER</b> attributes are added into Message metadata " +
|
||||||
"with specific prefix: <i>cs/shared/ss</i>. To access those attributes in other nodes this template can be used " +
|
"with specific prefix: <i>cs/shared/ss</i>. To access those attributes in other nodes this template can be used " +
|
||||||
|
|||||||
@ -16,14 +16,16 @@
|
|||||||
package org.thingsboard.rule.engine.metadata;
|
package org.thingsboard.rule.engine.metadata;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by ashvayka on 19.01.18.
|
* Created by ashvayka on 19.01.18.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class TbGetAttributesNodeConfiguration {
|
public class TbGetAttributesNodeConfiguration implements NodeConfiguration {
|
||||||
|
|
||||||
private List<String> clientAttributeNames;
|
private List<String> clientAttributeNames;
|
||||||
private List<String> sharedAttributeNames;
|
private List<String> sharedAttributeNames;
|
||||||
@ -31,4 +33,13 @@ public class TbGetAttributesNodeConfiguration {
|
|||||||
|
|
||||||
private List<String> latestTsKeyNames;
|
private List<String> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
|
|||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.ENRICHMENT,
|
type = ComponentType.ENRICHMENT,
|
||||||
name="customer attributes",
|
name="customer attributes",
|
||||||
|
configClazz = TbGetEntityAttrNodeConfiguration.class,
|
||||||
nodeDescription = "Add Originators Customer Attributes or Latest Telemetry into Message Metadata",
|
nodeDescription = "Add Originators Customer Attributes or Latest Telemetry into Message Metadata",
|
||||||
nodeDetails = "If Attributes enrichment configured, server scope attributes are added 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 " +
|
"To access those attributes in other nodes this template can be used " +
|
||||||
|
|||||||
@ -16,13 +16,25 @@
|
|||||||
package org.thingsboard.rule.engine.metadata;
|
package org.thingsboard.rule.engine.metadata;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TbGetEntityAttrNodeConfiguration {
|
public class TbGetEntityAttrNodeConfiguration implements NodeConfiguration {
|
||||||
|
|
||||||
private Map<String, String> attrMapping;
|
private Map<String, String> attrMapping;
|
||||||
private boolean isTelemetry = false;
|
private boolean isTelemetry = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbGetEntityAttrNodeConfiguration defaultConfiguration() {
|
||||||
|
TbGetEntityAttrNodeConfiguration configuration = new TbGetEntityAttrNodeConfiguration();
|
||||||
|
Map<String, String> attrMapping = new HashMap<>();
|
||||||
|
attrMapping.putIfAbsent("temperature", "tempo");
|
||||||
|
configuration.setAttrMapping(attrMapping);
|
||||||
|
configuration.setTelemetry(true);
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,11 +16,28 @@
|
|||||||
package org.thingsboard.rule.engine.metadata;
|
package org.thingsboard.rule.engine.metadata;
|
||||||
|
|
||||||
import lombok.Data;
|
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 org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfiguration {
|
public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfiguration {
|
||||||
|
|
||||||
private String relationType;
|
private String relationType;
|
||||||
private EntitySearchDirection direction;
|
private EntitySearchDirection direction;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbGetRelatedAttrNodeConfiguration defaultConfiguration() {
|
||||||
|
TbGetRelatedAttrNodeConfiguration configuration = new TbGetRelatedAttrNodeConfiguration();
|
||||||
|
Map<String, String> attrMapping = new HashMap<>();
|
||||||
|
attrMapping.putIfAbsent("temperature", "tempo");
|
||||||
|
configuration.setAttrMapping(attrMapping);
|
||||||
|
configuration.setTelemetry(true);
|
||||||
|
configuration.setRelationType(EntityRelation.CONTAINS_TYPE);
|
||||||
|
configuration.setDirection(EntitySearchDirection.FROM);
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
|
|||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.ENRICHMENT,
|
type = ComponentType.ENRICHMENT,
|
||||||
name="related attributes",
|
name="related attributes",
|
||||||
|
configClazz = TbGetRelatedAttrNodeConfiguration.class,
|
||||||
nodeDescription = "Add Originators Related Entity Attributes or Latest Telemetry into Message Metadata",
|
nodeDescription = "Add Originators Related Entity Attributes or Latest Telemetry into Message Metadata",
|
||||||
nodeDetails = "Related Entity found using configured relation direction and Relation Type. " +
|
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. " +
|
"If multiple Related Entities are found, only first Entity is used for attributes enrichment, other entities are discarded. " +
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
|
|||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.ENRICHMENT,
|
type = ComponentType.ENRICHMENT,
|
||||||
name="tenant attributes",
|
name="tenant attributes",
|
||||||
|
configClazz = TbGetEntityAttrNodeConfiguration.class,
|
||||||
nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata",
|
nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata",
|
||||||
nodeDetails = "If Attributes enrichment configured, server scope attributes are added 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 " +
|
"To access those attributes in other nodes this template can be used " +
|
||||||
|
|||||||
@ -36,6 +36,7 @@ import java.util.HashSet;
|
|||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.TRANSFORMATION,
|
type = ComponentType.TRANSFORMATION,
|
||||||
name="change originator",
|
name="change originator",
|
||||||
|
configClazz = TbChangeOriginatorNodeConfiguration.class,
|
||||||
nodeDescription = "Change Message Originator To Tenant/Customer/Related Entity",
|
nodeDescription = "Change Message Originator To Tenant/Customer/Related Entity",
|
||||||
nodeDetails = "Related Entity found using configured relation direction and Relation Type. " +
|
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. ")
|
"If multiple Related Entities are found, only first Entity is used as new Originator, other entities are discarded. ")
|
||||||
|
|||||||
@ -16,12 +16,24 @@
|
|||||||
package org.thingsboard.rule.engine.transform;
|
package org.thingsboard.rule.engine.transform;
|
||||||
|
|
||||||
import lombok.Data;
|
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 org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TbChangeOriginatorNodeConfiguration extends TbTransformNodeConfiguration{
|
public class TbChangeOriginatorNodeConfiguration extends TbTransformNodeConfiguration implements NodeConfiguration {
|
||||||
|
|
||||||
private String originatorSource;
|
private String originatorSource;
|
||||||
private EntitySearchDirection direction;
|
private EntitySearchDirection direction;
|
||||||
private String relationType;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import javax.script.Bindings;
|
|||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.TRANSFORMATION,
|
type = ComponentType.TRANSFORMATION,
|
||||||
name = "script",
|
name = "script",
|
||||||
|
configClazz = TbTransformMsgNodeConfiguration.class,
|
||||||
nodeDescription = "Change Message payload and Metadata using JavaScript",
|
nodeDescription = "Change Message payload and Metadata using JavaScript",
|
||||||
nodeDetails = "JavaScript function recieve 2 input parameters that can be changed inside.<br/> " +
|
nodeDetails = "JavaScript function recieve 2 input parameters that can be changed inside.<br/> " +
|
||||||
"<code>meta</code> - is a Message metadata.<br/>" +
|
"<code>meta</code> - is a Message metadata.<br/>" +
|
||||||
|
|||||||
@ -16,9 +16,18 @@
|
|||||||
package org.thingsboard.rule.engine.transform;
|
package org.thingsboard.rule.engine.transform;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TbTransformMsgNodeConfiguration extends TbTransformNodeConfiguration {
|
public class TbTransformMsgNodeConfiguration extends TbTransformNodeConfiguration implements NodeConfiguration {
|
||||||
|
|
||||||
private String jsScript;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -153,16 +153,21 @@ function RuleChainService($http, $q, $filter, types, componentDescriptorService)
|
|||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRuleNodeSupportedLinks(nodeType) { //eslint-disable-line
|
function getRuleNodeSupportedLinks(component) {
|
||||||
//TODO:
|
var relationTypes = component.configurationDescriptor.nodeDefinition.relationTypes;
|
||||||
var deferred = $q.defer();
|
var customRelations = component.configurationDescriptor.nodeDefinition.customRelations;
|
||||||
var linkLabels = [
|
var linkLabels = [];
|
||||||
{ name: 'Success', custom: false },
|
for (var i=0;i<relationTypes.length;i++) {
|
||||||
{ name: 'Fail', custom: false },
|
linkLabels.push({
|
||||||
{ name: 'Custom', custom: true },
|
name: relationTypes[i], custom: false
|
||||||
];
|
});
|
||||||
deferred.resolve(linkLabels);
|
}
|
||||||
return deferred.promise;
|
if (customRelations) {
|
||||||
|
linkLabels.push(
|
||||||
|
{ name: 'Custom', custom: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return linkLabels;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRuleNodeComponents() {
|
function getRuleNodeComponents() {
|
||||||
|
|||||||
165
ui/src/app/components/json-object-edit.directive.js
Normal file
165
ui/src/app/components/json-object-edit.directive.js
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
import './json-object-edit.scss';
|
||||||
|
|
||||||
|
import 'brace/ext/language_tools';
|
||||||
|
import 'brace/mode/json';
|
||||||
|
import 'ace-builds/src-min-noconflict/snippets/json';
|
||||||
|
|
||||||
|
/* eslint-disable import/no-unresolved, import/default */
|
||||||
|
|
||||||
|
import jsonObjectEditTemplate from './json-object-edit.tpl.html';
|
||||||
|
|
||||||
|
/* eslint-enable import/no-unresolved, import/default */
|
||||||
|
|
||||||
|
export default angular.module('thingsboard.directives.jsonObjectEdit', [])
|
||||||
|
.directive('tbJsonObjectEdit', JsonObjectEdit)
|
||||||
|
.name;
|
||||||
|
|
||||||
|
/*@ngInject*/
|
||||||
|
function JsonObjectEdit($compile, $templateCache, toast, utils) {
|
||||||
|
|
||||||
|
var linker = function (scope, element, attrs, ngModelCtrl) {
|
||||||
|
var template = $templateCache.get(jsonObjectEditTemplate);
|
||||||
|
element.html(template);
|
||||||
|
|
||||||
|
scope.label = attrs.label;
|
||||||
|
|
||||||
|
scope.objectValid = true;
|
||||||
|
scope.validationError = '';
|
||||||
|
|
||||||
|
scope.json_editor;
|
||||||
|
|
||||||
|
scope.onFullscreenChanged = function () {
|
||||||
|
updateEditorSize();
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateEditorSize() {
|
||||||
|
if (scope.json_editor) {
|
||||||
|
scope.json_editor.resize();
|
||||||
|
scope.json_editor.renderer.updateFull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.jsonEditorOptions = {
|
||||||
|
useWrapMode: true,
|
||||||
|
mode: 'json',
|
||||||
|
advanced: {
|
||||||
|
enableSnippets: true,
|
||||||
|
enableBasicAutocompletion: true,
|
||||||
|
enableLiveAutocompletion: true
|
||||||
|
},
|
||||||
|
onLoad: function (_ace) {
|
||||||
|
scope.json_editor = _ace;
|
||||||
|
scope.json_editor.session.on("change", function () {
|
||||||
|
scope.cleanupJsonErrors();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.cleanupJsonErrors = function () {
|
||||||
|
toast.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.updateValidity = function () {
|
||||||
|
ngModelCtrl.$setValidity('objectValid', scope.objectValid);
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.$watch('contentBody', function (newVal, prevVal) {
|
||||||
|
if (!angular.equals(newVal, prevVal)) {
|
||||||
|
var object = scope.validate();
|
||||||
|
ngModelCtrl.$setViewValue(object);
|
||||||
|
scope.updateValidity();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ngModelCtrl.$render = function () {
|
||||||
|
var object = ngModelCtrl.$viewValue;
|
||||||
|
var content = '';
|
||||||
|
try {
|
||||||
|
if (object) {
|
||||||
|
content = angular.toJson(object, true);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
scope.contentBody = content;
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.showError = function (error) {
|
||||||
|
var toastParent = angular.element('#tb-json-panel', element);
|
||||||
|
toast.showError(error, toastParent, 'bottom left');
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.validate = function () {
|
||||||
|
if (!scope.contentBody || !scope.contentBody.length) {
|
||||||
|
if (scope.required) {
|
||||||
|
scope.validationError = 'Json object is required.';
|
||||||
|
scope.objectValid = false;
|
||||||
|
} else {
|
||||||
|
scope.validationError = '';
|
||||||
|
scope.objectValid = true;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
var object = angular.fromJson(scope.contentBody);
|
||||||
|
scope.validationError = '';
|
||||||
|
scope.objectValid = true;
|
||||||
|
return object;
|
||||||
|
} catch (e) {
|
||||||
|
var details = utils.parseException(e);
|
||||||
|
var errorInfo = 'Error:';
|
||||||
|
if (details.name) {
|
||||||
|
errorInfo += ' ' + details.name + ':';
|
||||||
|
}
|
||||||
|
if (details.message) {
|
||||||
|
errorInfo += ' ' + details.message;
|
||||||
|
}
|
||||||
|
scope.validationError = errorInfo;
|
||||||
|
scope.objectValid = false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.$on('form-submit', function () {
|
||||||
|
if (!scope.readonly) {
|
||||||
|
scope.cleanupJsonErrors();
|
||||||
|
if (!scope.objectValid) {
|
||||||
|
scope.showError(scope.validationError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.$on('update-ace-editor-size', function () {
|
||||||
|
updateEditorSize();
|
||||||
|
});
|
||||||
|
|
||||||
|
$compile(element.contents())(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: "E",
|
||||||
|
require: "^ngModel",
|
||||||
|
scope: {
|
||||||
|
required:'=ngRequired',
|
||||||
|
readonly:'=ngReadonly',
|
||||||
|
fillHeight:'=?'
|
||||||
|
},
|
||||||
|
link: linker
|
||||||
|
};
|
||||||
|
}
|
||||||
35
ui/src/app/components/json-object-edit.scss
Normal file
35
ui/src/app/components/json-object-edit.scss
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 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-json-object-edit {
|
||||||
|
position: relative;
|
||||||
|
.fill-height {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-json-object-panel {
|
||||||
|
margin-left: 15px;
|
||||||
|
border: 1px solid #C0C0C0;
|
||||||
|
height: 100%;
|
||||||
|
#tb-json-input {
|
||||||
|
min-width: 200px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
&:not(.fill-height) {
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
ui/src/app/components/json-object-edit.tpl.html
Normal file
34
ui/src/app/components/json-object-edit.tpl.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<div style="background: #fff;" ng-class="{'fill-height': fillHeight}" tb-expand-fullscreen fullscreen-zindex="100" expand-button-id="expand-button" on-fullscreen-changed="onFullscreenChanged()" layout="column">
|
||||||
|
<div layout="row" layout-align="start center">
|
||||||
|
<label class="tb-title no-padding"
|
||||||
|
ng-class="{'tb-required': required,
|
||||||
|
'tb-readonly': readonly,
|
||||||
|
'tb-error': !objectValid}">{{ label }}</label>
|
||||||
|
<span flex></span>
|
||||||
|
<md-button id="expand-button" aria-label="Fullscreen" class="md-icon-button tb-md-32 tb-fullscreen-button-style"></md-button>
|
||||||
|
</div>
|
||||||
|
<div flex id="tb-json-panel" class="tb-json-object-panel" layout="column">
|
||||||
|
<div flex id="tb-json-input" ng-class="{'fill-height': fillHeight}"
|
||||||
|
ng-readonly="readonly"
|
||||||
|
ui-ace="jsonEditorOptions"
|
||||||
|
ng-model="contentBody">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -29,6 +29,7 @@ import thingsboardNoAnimate from '../components/no-animate.directive';
|
|||||||
import thingsboardOnFinishRender from '../components/finish-render.directive';
|
import thingsboardOnFinishRender from '../components/finish-render.directive';
|
||||||
import thingsboardSideMenu from '../components/side-menu.directive';
|
import thingsboardSideMenu from '../components/side-menu.directive';
|
||||||
import thingsboardDashboardAutocomplete from '../components/dashboard-autocomplete.directive';
|
import thingsboardDashboardAutocomplete from '../components/dashboard-autocomplete.directive';
|
||||||
|
import thingsboardJsonObjectEdit from '../components/json-object-edit.directive';
|
||||||
|
|
||||||
import thingsboardUserMenu from './user-menu.directive';
|
import thingsboardUserMenu from './user-menu.directive';
|
||||||
|
|
||||||
@ -90,7 +91,8 @@ export default angular.module('thingsboard.home', [
|
|||||||
thingsboardNoAnimate,
|
thingsboardNoAnimate,
|
||||||
thingsboardOnFinishRender,
|
thingsboardOnFinishRender,
|
||||||
thingsboardSideMenu,
|
thingsboardSideMenu,
|
||||||
thingsboardDashboardAutocomplete
|
thingsboardDashboardAutocomplete,
|
||||||
|
thingsboardJsonObjectEdit
|
||||||
])
|
])
|
||||||
.config(HomeRoutes)
|
.config(HomeRoutes)
|
||||||
.controller('HomeController', HomeController)
|
.controller('HomeController', HomeController)
|
||||||
|
|||||||
@ -1179,6 +1179,7 @@ export default angular.module('thingsboard.locale', [])
|
|||||||
"delete": "Delete rule node",
|
"delete": "Delete rule node",
|
||||||
"rulenode-details": "Rule node details",
|
"rulenode-details": "Rule node details",
|
||||||
"debug-mode": "Debug mode",
|
"debug-mode": "Debug mode",
|
||||||
|
"configuration": "Configuration",
|
||||||
"link-details": "Rule node link details",
|
"link-details": "Rule node link details",
|
||||||
"add-link": "Add link",
|
"add-link": "Add link",
|
||||||
"link-label": "Link label",
|
"link-label": "Link label",
|
||||||
|
|||||||
@ -151,6 +151,9 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
|
|||||||
},
|
},
|
||||||
'mouseLeave': function () {
|
'mouseLeave': function () {
|
||||||
destroyTooltips();
|
destroyTooltips();
|
||||||
|
},
|
||||||
|
'mouseDown': function () {
|
||||||
|
destroyTooltips();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -226,17 +229,13 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
|
|||||||
edgeDoubleClick: function (event, edge) {
|
edgeDoubleClick: function (event, edge) {
|
||||||
var sourceNode = vm.modelservice.nodes.getNodeByConnectorId(edge.source);
|
var sourceNode = vm.modelservice.nodes.getNodeByConnectorId(edge.source);
|
||||||
if (sourceNode.component.type != types.ruleNodeType.INPUT.value) {
|
if (sourceNode.component.type != types.ruleNodeType.INPUT.value) {
|
||||||
ruleChainService.getRuleNodeSupportedLinks(sourceNode.component.clazz).then(
|
|
||||||
(labels) => {
|
|
||||||
vm.isEditingRuleNode = false;
|
vm.isEditingRuleNode = false;
|
||||||
vm.editingRuleNode = null;
|
vm.editingRuleNode = null;
|
||||||
vm.editingRuleNodeLinkLabels = labels;
|
vm.editingRuleNodeLinkLabels = ruleChainService.getRuleNodeSupportedLinks(sourceNode.component);
|
||||||
vm.isEditingRuleNodeLink = true;
|
vm.isEditingRuleNodeLink = true;
|
||||||
vm.editingRuleNodeLinkIndex = vm.ruleChainModel.edges.indexOf(edge);
|
vm.editingRuleNodeLinkIndex = vm.ruleChainModel.edges.indexOf(edge);
|
||||||
vm.editingRuleNodeLink = angular.copy(edge);
|
vm.editingRuleNodeLink = angular.copy(edge);
|
||||||
}
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
nodeCallbacks: {
|
nodeCallbacks: {
|
||||||
'doubleClick': function (event, node) {
|
'doubleClick': function (event, node) {
|
||||||
@ -267,8 +266,7 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
|
|||||||
deferred.resolve(edge);
|
deferred.resolve(edge);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ruleChainService.getRuleNodeSupportedLinks(sourceNode.component.clazz).then(
|
var labels = ruleChainService.getRuleNodeSupportedLinks(sourceNode.component);
|
||||||
(labels) => {
|
|
||||||
addRuleNodeLink(event, edge, labels).then(
|
addRuleNodeLink(event, edge, labels).then(
|
||||||
(link) => {
|
(link) => {
|
||||||
deferred.resolve(link);
|
deferred.resolve(link);
|
||||||
@ -277,11 +275,6 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
|
|||||||
deferred.reject();
|
deferred.reject();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
|
||||||
() => {
|
|
||||||
deferred.reject();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
},
|
},
|
||||||
@ -309,20 +302,15 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
|
|||||||
y: 10+50*model.nodes.length,
|
y: 10+50*model.nodes.length,
|
||||||
connectors: []
|
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(
|
node.connectors.push(
|
||||||
{
|
{
|
||||||
type: flowchartConstants.leftConnectorType,
|
type: flowchartConstants.leftConnectorType,
|
||||||
id: model.nodes.length * 2
|
id: model.nodes.length * 2
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
if (ruleNodeComponent.configurationDescriptor.nodeDefinition.outEnabled) {
|
||||||
node.connectors.push(
|
node.connectors.push(
|
||||||
{
|
{
|
||||||
type: flowchartConstants.rightConnectorType,
|
type: flowchartConstants.rightConnectorType,
|
||||||
@ -398,17 +386,24 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
|
|||||||
name: ruleNode.name,
|
name: ruleNode.name,
|
||||||
nodeClass: vm.types.ruleNodeType[component.type].nodeClass,
|
nodeClass: vm.types.ruleNodeType[component.type].nodeClass,
|
||||||
icon: vm.types.ruleNodeType[component.type].icon,
|
icon: vm.types.ruleNodeType[component.type].icon,
|
||||||
connectors: [
|
connectors: []
|
||||||
|
};
|
||||||
|
if (component.configurationDescriptor.nodeDefinition.inEnabled) {
|
||||||
|
node.connectors.push(
|
||||||
{
|
{
|
||||||
type: flowchartConstants.leftConnectorType,
|
type: flowchartConstants.leftConnectorType,
|
||||||
id: vm.nextConnectorID++
|
id: vm.nextConnectorID++
|
||||||
},
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (component.configurationDescriptor.nodeDefinition.outEnabled) {
|
||||||
|
node.connectors.push(
|
||||||
{
|
{
|
||||||
type: flowchartConstants.rightConnectorType,
|
type: flowchartConstants.rightConnectorType,
|
||||||
id: vm.nextConnectorID++
|
id: vm.nextConnectorID++
|
||||||
}
|
}
|
||||||
]
|
);
|
||||||
};
|
}
|
||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
vm.ruleChainModel.nodes.push(node);
|
vm.ruleChainModel.nodes.push(node);
|
||||||
}
|
}
|
||||||
@ -590,6 +585,9 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addRuleNode($event, ruleNode) {
|
function addRuleNode($event, ruleNode) {
|
||||||
|
|
||||||
|
ruleNode.configuration = angular.copy(ruleNode.component.configurationDescriptor.nodeDefinition.defaultConfiguration);
|
||||||
|
|
||||||
$mdDialog.show({
|
$mdDialog.show({
|
||||||
controller: 'AddRuleNodeController',
|
controller: 'AddRuleNodeController',
|
||||||
controllerAs: 'vm',
|
controllerAs: 'vm',
|
||||||
@ -601,13 +599,15 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
|
|||||||
}).then(function (ruleNode) {
|
}).then(function (ruleNode) {
|
||||||
ruleNode.id = vm.nextNodeID++;
|
ruleNode.id = vm.nextNodeID++;
|
||||||
ruleNode.connectors = [];
|
ruleNode.connectors = [];
|
||||||
|
if (ruleNode.component.configurationDescriptor.nodeDefinition.inEnabled) {
|
||||||
ruleNode.connectors.push(
|
ruleNode.connectors.push(
|
||||||
{
|
{
|
||||||
id: vm.nextConnectorID++,
|
id: vm.nextConnectorID++,
|
||||||
type: flowchartConstants.leftConnectorType
|
type: flowchartConstants.leftConnectorType
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (ruleNode.component.type != types.ruleNodeType.RULE_CHAIN.value) {
|
}
|
||||||
|
if (ruleNode.component.configurationDescriptor.nodeDefinition.outEnabled) {
|
||||||
ruleNode.connectors.push(
|
ruleNode.connectors.push(
|
||||||
{
|
{
|
||||||
id: vm.nextConnectorID++,
|
id: vm.nextConnectorID++,
|
||||||
|
|||||||
@ -38,6 +38,11 @@
|
|||||||
ng-model="ruleNode.debugMode">{{ 'rulenode.debug-mode' | translate }}
|
ng-model="ruleNode.debugMode">{{ 'rulenode.debug-mode' | translate }}
|
||||||
</md-checkbox>
|
</md-checkbox>
|
||||||
</md-input-container>
|
</md-input-container>
|
||||||
|
<tb-json-object-edit class="tb-rule-node-configuration-json" ng-model="ruleNode.configuration"
|
||||||
|
label="{{ 'rulenode.configuration' | translate }}"
|
||||||
|
ng-required="true"
|
||||||
|
fill-height="true">
|
||||||
|
</tb-json-object-edit>
|
||||||
<md-input-container class="md-block">
|
<md-input-container class="md-block">
|
||||||
<label translate>rulenode.description</label>
|
<label translate>rulenode.description</label>
|
||||||
<textarea ng-model="ruleNode.additionalInfo.description" rows="2"></textarea>
|
<textarea ng-model="ruleNode.additionalInfo.description" rows="2"></textarea>
|
||||||
|
|||||||
@ -14,6 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import './rulenode.scss';
|
||||||
|
|
||||||
/* eslint-disable import/no-unresolved, import/default */
|
/* eslint-disable import/no-unresolved, import/default */
|
||||||
|
|
||||||
import ruleNodeFieldsetTemplate from './rulenode-fieldset.tpl.html';
|
import ruleNodeFieldsetTemplate from './rulenode-fieldset.tpl.html';
|
||||||
|
|||||||
22
ui/src/app/rulechain/rulenode.scss
Normal file
22
ui/src/app/rulechain/rulenode.scss
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@
|
|||||||
id="{{node.id}}"
|
id="{{node.id}}"
|
||||||
ng-attr-style="position: absolute; top: {{ node.y }}px; left: {{ node.x }}px;"
|
ng-attr-style="position: absolute; top: {{ node.y }}px; left: {{ node.x }}px;"
|
||||||
ng-dblclick="callbacks.doubleClick($event, node)"
|
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-mouseenter="callbacks.mouseEnter($event, node)"
|
||||||
ng-mouseleave="callbacks.mouseLeave($event, node)">
|
ng-mouseleave="callbacks.mouseLeave($event, node)">
|
||||||
<div class="tb-rule-node {{node.nodeClass}}">
|
<div class="tb-rule-node {{node.nodeClass}}">
|
||||||
|
|||||||
@ -203,6 +203,12 @@ md-sidenav {
|
|||||||
* THINGSBOARD SPECIFIC
|
* 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 {
|
label {
|
||||||
&.tb-title {
|
&.tb-title {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@ -213,6 +219,18 @@ label {
|
|||||||
&.no-padding {
|
&.no-padding {
|
||||||
padding-bottom: 0px;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user