Rule Node Configuration
This commit is contained in:
		
							parent
							
								
									73473e3beb
								
							
						
					
					
						commit
						adb71ecfe7
					
				@ -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<? extends NodeConfiguration> configClazz = nodeAnnotation.configClazz();
 | 
			
		||||
        NodeConfiguration config = configClazz.newInstance();
 | 
			
		||||
        NodeConfiguration defaultConfiguration = config.defaultConfiguration();
 | 
			
		||||
        nodeDefinition.setDefaultConfiguration(mapper.valueToTree(defaultConfiguration));
 | 
			
		||||
        return nodeDefinition;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -234,7 +234,7 @@ caffeine:
 | 
			
		||||
  specs:
 | 
			
		||||
    relations:
 | 
			
		||||
      timeToLiveInMinutes: 1440
 | 
			
		||||
      maxSize: 100000
 | 
			
		||||
      maxSize: 0
 | 
			
		||||
    deviceCredentials:
 | 
			
		||||
      timeToLiveInMinutes: 1440
 | 
			
		||||
      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();
 | 
			
		||||
 | 
			
		||||
    Class<? extends NodeConfiguration> 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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,2 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@ -1,2 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@ -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 <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;
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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. " +
 | 
			
		||||
 | 
			
		||||
@ -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<String> 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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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 <b>Success</b> chain, otherwise <b>Failure</b> chain is used.")
 | 
			
		||||
 | 
			
		||||
@ -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<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
 | 
			
		||||
@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, <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 " +
 | 
			
		||||
 | 
			
		||||
@ -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<String> clientAttributeNames;
 | 
			
		||||
    private List<String> sharedAttributeNames;
 | 
			
		||||
@ -31,4 +33,13 @@ public class TbGetAttributesNodeConfiguration {
 | 
			
		||||
 | 
			
		||||
    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(
 | 
			
		||||
        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 " +
 | 
			
		||||
 | 
			
		||||
@ -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<String, String> attrMapping;
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
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<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(
 | 
			
		||||
        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. " +
 | 
			
		||||
 | 
			
		||||
@ -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 " +
 | 
			
		||||
 | 
			
		||||
@ -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. ")
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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.<br/> " +
 | 
			
		||||
                "<code>meta</code> - is a Message metadata.<br/>" +
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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<relationTypes.length;i++) {
 | 
			
		||||
            linkLabels.push({
 | 
			
		||||
                name: relationTypes[i], custom: false
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        if (customRelations) {
 | 
			
		||||
            linkLabels.push(
 | 
			
		||||
                { name: 'Custom', custom: true }
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        return linkLabels;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 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)
 | 
			
		||||
 | 
			
		||||
@ -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",
 | 
			
		||||
 | 
			
		||||
@ -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++,
 | 
			
		||||
 | 
			
		||||
@ -38,6 +38,11 @@
 | 
			
		||||
                             ng-model="ruleNode.debugMode">{{ 'rulenode.debug-mode' | translate }}
 | 
			
		||||
                </md-checkbox>
 | 
			
		||||
            </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">
 | 
			
		||||
                <label translate>rulenode.description</label>
 | 
			
		||||
                <textarea ng-model="ruleNode.additionalInfo.description" rows="2"></textarea>
 | 
			
		||||
 | 
			
		||||
@ -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';
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										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}}"
 | 
			
		||||
        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)">
 | 
			
		||||
    <div class="tb-rule-node {{node.nodeClass}}">
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user