Enrichment Rule nodes config UI
This commit is contained in:
		
							parent
							
								
									9c0f6e9925
								
							
						
					
					
						commit
						c9717f4d1d
					
				@ -0,0 +1,31 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.data;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityTypeFilter;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class RelationsQuery {
 | 
			
		||||
 | 
			
		||||
    private EntitySearchDirection direction;
 | 
			
		||||
    private int maxLevel = 1;
 | 
			
		||||
    private List<EntityTypeFilter> filters;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -43,7 +43,9 @@ import static org.thingsboard.server.common.data.DataConstants.*;
 | 
			
		||||
          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 " +
 | 
			
		||||
                "<code>metadata.cs.temperature</code> or <code>metadata.shared.limit</code> " +
 | 
			
		||||
                "If Latest Telemetry enrichment configured, latest telemetry added into metadata without prefix.")
 | 
			
		||||
                "If Latest Telemetry enrichment configured, latest telemetry added into metadata without prefix.",
 | 
			
		||||
        uiResources = {"static/rulenode/rulenode-core-config.js"},
 | 
			
		||||
        configDirective = "tbEnrichmentNodeOriginatorAttributesConfig")
 | 
			
		||||
public class TbGetAttributesNode implements TbNode {
 | 
			
		||||
 | 
			
		||||
    private TbGetAttributesNodeConfiguration config;
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,9 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
 | 
			
		||||
        nodeDescription = "Add Originators Customer Attributes or Latest Telemetry into Message Metadata",
 | 
			
		||||
        nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message metadata. " +
 | 
			
		||||
                "To access those attributes in other nodes this template can be used " +
 | 
			
		||||
                "<code>metadata.temperature</code>. If Latest Telemetry enrichment configured, latest telemetry added into metadata")
 | 
			
		||||
                "<code>metadata.temperature</code>. If Latest Telemetry enrichment configured, latest telemetry added into metadata",
 | 
			
		||||
        uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
 | 
			
		||||
        configDirective = "tbEnrichmentNodeCustomerAttributesConfig")
 | 
			
		||||
public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 | 
			
		||||
@ -16,18 +16,19 @@
 | 
			
		||||
package org.thingsboard.rule.engine.metadata;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
 | 
			
		||||
import org.thingsboard.rule.engine.data.RelationsQuery;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityRelation;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityTypeFilter;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfiguration {
 | 
			
		||||
 | 
			
		||||
    private String relationType;
 | 
			
		||||
    private EntitySearchDirection direction;
 | 
			
		||||
    private RelationsQuery relationsQuery;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public TbGetRelatedAttrNodeConfiguration defaultConfiguration() {
 | 
			
		||||
@ -36,8 +37,14 @@ public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfig
 | 
			
		||||
        attrMapping.putIfAbsent("temperature", "tempo");
 | 
			
		||||
        configuration.setAttrMapping(attrMapping);
 | 
			
		||||
        configuration.setTelemetry(true);
 | 
			
		||||
        configuration.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
        configuration.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
 | 
			
		||||
        RelationsQuery relationsQuery = new RelationsQuery();
 | 
			
		||||
        relationsQuery.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        relationsQuery.setMaxLevel(1);
 | 
			
		||||
        EntityTypeFilter entityTypeFilter = new EntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.emptyList());
 | 
			
		||||
        relationsQuery.setFilters(Collections.singletonList(entityTypeFilter));
 | 
			
		||||
        configuration.setRelationsQuery(relationsQuery);
 | 
			
		||||
 | 
			
		||||
        return configuration;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,10 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
 | 
			
		||||
                "If multiple Related Entities are found, only first Entity is used for attributes enrichment, other entities are discarded. " +
 | 
			
		||||
                "If Attributes enrichment configured, server scope attributes are added into Message metadata. " +
 | 
			
		||||
                "To access those attributes in other nodes this template can be used " +
 | 
			
		||||
                "<code>metadata.temperature</code>. If Latest Telemetry enrichment configured, latest telemetry added into metadata")
 | 
			
		||||
                "<code>metadata.temperature</code>. If Latest Telemetry enrichment configured, latest telemetry added into metadata",
 | 
			
		||||
        uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
 | 
			
		||||
        configDirective = "tbEnrichmentNodeRelatedAttributesConfig")
 | 
			
		||||
 | 
			
		||||
public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> {
 | 
			
		||||
 | 
			
		||||
    private TbGetRelatedAttrNodeConfiguration config;
 | 
			
		||||
@ -45,6 +48,6 @@ public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected ListenableFuture<EntityId> findEntityAsync(TbContext ctx, EntityId originator) {
 | 
			
		||||
        return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, originator, config.getDirection(), config.getRelationType());
 | 
			
		||||
        return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, originator, config.getRelationsQuery());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,9 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
 | 
			
		||||
        nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata",
 | 
			
		||||
        nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message metadata. " +
 | 
			
		||||
                "To access those attributes in other nodes this template can be used " +
 | 
			
		||||
                "<code>metadata.temperature</code>. If Latest Telemetry enrichment configured, latest telemetry added into metadata")
 | 
			
		||||
                "<code>metadata.temperature</code>. If Latest Telemetry enrichment configured, latest telemetry added into metadata",
 | 
			
		||||
        uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
 | 
			
		||||
        configDirective = "tbEnrichmentNodeTenantAttributesConfig")
 | 
			
		||||
public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ public class TbChangeOriginatorNode extends TbAbstractTransformNode {
 | 
			
		||||
            case TENANT_SOURCE:
 | 
			
		||||
                return EntitiesTenantIdAsyncLoader.findEntityIdAsync(ctx, original);
 | 
			
		||||
            case RELATED_SOURCE:
 | 
			
		||||
                return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, original, config.getDirection(), config.getRelationType());
 | 
			
		||||
                return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, original, config.getRelationsQuery());
 | 
			
		||||
            default:
 | 
			
		||||
                return Futures.immediateFailedFuture(new IllegalStateException("Unexpected originator source " + config.getOriginatorSource()));
 | 
			
		||||
        }
 | 
			
		||||
@ -82,9 +82,9 @@ public class TbChangeOriginatorNode extends TbAbstractTransformNode {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (conf.getOriginatorSource().equals(RELATED_SOURCE)) {
 | 
			
		||||
            if (conf.getDirection() == null || StringUtils.isBlank(conf.getRelationType())) {
 | 
			
		||||
                log.error("Related source for TbChangeOriginatorNode should have direction and relationType. Actual [{}] [{}]",
 | 
			
		||||
                        conf.getDirection(), conf.getRelationType());
 | 
			
		||||
            if (conf.getRelationsQuery() == null) {
 | 
			
		||||
                log.error("Related source for TbChangeOriginatorNode should have relations query. Actual [{}]",
 | 
			
		||||
                        conf.getRelationsQuery());
 | 
			
		||||
                throw new IllegalArgumentException("Wrong config for RElated Source in TbChangeOriginatorNode" + conf.getOriginatorSource());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -17,22 +17,32 @@ package org.thingsboard.rule.engine.transform;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
 | 
			
		||||
import org.thingsboard.rule.engine.data.RelationsQuery;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityRelation;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityTypeFilter;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class TbChangeOriginatorNodeConfiguration extends TbTransformNodeConfiguration implements NodeConfiguration {
 | 
			
		||||
 | 
			
		||||
    private String originatorSource;
 | 
			
		||||
    private EntitySearchDirection direction;
 | 
			
		||||
    private String relationType;
 | 
			
		||||
 | 
			
		||||
    private RelationsQuery relationsQuery;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public TbChangeOriginatorNodeConfiguration defaultConfiguration() {
 | 
			
		||||
        TbChangeOriginatorNodeConfiguration configuration = new TbChangeOriginatorNodeConfiguration();
 | 
			
		||||
        configuration.setOriginatorSource(TbChangeOriginatorNode.CUSTOMER_SOURCE);
 | 
			
		||||
        configuration.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        configuration.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
 | 
			
		||||
        RelationsQuery relationsQuery = new RelationsQuery();
 | 
			
		||||
        relationsQuery.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        relationsQuery.setMaxLevel(1);
 | 
			
		||||
        EntityTypeFilter entityTypeFilter = new EntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.emptyList());
 | 
			
		||||
        relationsQuery.setFilters(Collections.singletonList(entityTypeFilter));
 | 
			
		||||
        configuration.setRelationsQuery(relationsQuery);
 | 
			
		||||
 | 
			
		||||
        configuration.setStartNewChain(false);
 | 
			
		||||
        return configuration;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -20,32 +20,41 @@ import com.google.common.util.concurrent.Futures;
 | 
			
		||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
			
		||||
import org.apache.commons.collections.CollectionUtils;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbContext;
 | 
			
		||||
import org.thingsboard.rule.engine.data.RelationsQuery;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityRelation;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
 | 
			
		||||
import org.thingsboard.server.dao.relation.RelationService;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static org.thingsboard.server.common.data.relation.RelationTypeGroup.COMMON;
 | 
			
		||||
 | 
			
		||||
public class EntitiesRelatedEntityIdAsyncLoader {
 | 
			
		||||
 | 
			
		||||
    public static ListenableFuture<EntityId> findEntityAsync(TbContext ctx, EntityId originator,
 | 
			
		||||
                                                             EntitySearchDirection direction, String relationType) {
 | 
			
		||||
                                                             RelationsQuery relationsQuery) {
 | 
			
		||||
        RelationService relationService = ctx.getRelationService();
 | 
			
		||||
        if (direction == EntitySearchDirection.FROM) {
 | 
			
		||||
            ListenableFuture<List<EntityRelation>> asyncRelation = relationService.findByFromAndTypeAsync(originator, relationType, COMMON);
 | 
			
		||||
        EntityRelationsQuery query = buildQuery(originator, relationsQuery);
 | 
			
		||||
        ListenableFuture<List<EntityRelation>> asyncRelation = relationService.findByQuery(query);
 | 
			
		||||
        if (relationsQuery.getDirection() == EntitySearchDirection.FROM) {
 | 
			
		||||
            return Futures.transform(asyncRelation, (AsyncFunction<? super List<EntityRelation>, EntityId>)
 | 
			
		||||
                    r -> CollectionUtils.isNotEmpty(r) ? Futures.immediateFuture(r.get(0).getTo())
 | 
			
		||||
                            : Futures.immediateFailedFuture(new IllegalStateException("Relation not found")));
 | 
			
		||||
        } else if (direction == EntitySearchDirection.TO) {
 | 
			
		||||
            ListenableFuture<List<EntityRelation>> asyncRelation = relationService.findByToAndTypeAsync(originator, relationType, COMMON);
 | 
			
		||||
        } else if (relationsQuery.getDirection() == EntitySearchDirection.TO) {
 | 
			
		||||
            return Futures.transform(asyncRelation, (AsyncFunction<? super List<EntityRelation>, EntityId>)
 | 
			
		||||
                    r -> CollectionUtils.isNotEmpty(r) ? Futures.immediateFuture(r.get(0).getFrom())
 | 
			
		||||
                            : Futures.immediateFailedFuture(new IllegalStateException("Relation not found")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Futures.immediateFailedFuture(new IllegalStateException("Unknown direction"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static EntityRelationsQuery buildQuery(EntityId originator, RelationsQuery relationsQuery) {
 | 
			
		||||
        EntityRelationsQuery query = new EntityRelationsQuery();
 | 
			
		||||
        RelationsSearchParameters parameters = new RelationsSearchParameters(originator,
 | 
			
		||||
                relationsQuery.getDirection(), relationsQuery.getMaxLevel());
 | 
			
		||||
        query.setParameters(parameters);
 | 
			
		||||
        query.setFilters(relationsQuery.getFilters());
 | 
			
		||||
        return query;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,2 +1,2 @@
 | 
			
		||||
.tb-message-type-autocomplete .tb-not-found{display:block;line-height:1.5;height:48px}.tb-message-type-autocomplete .tb-not-found .tb-no-entries{line-height:48px}.tb-message-type-autocomplete li{height:auto!important;white-space:normal!important}
 | 
			
		||||
.tb-message-type-autocomplete .tb-not-found{display:block;line-height:1.5;height:48px}.tb-message-type-autocomplete .tb-not-found .tb-no-entries{line-height:48px}.tb-message-type-autocomplete li{height:auto!important;white-space:normal!important}.tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}.tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}.tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}.tb-kv-map-config .body .row{padding-top:5px;max-height:40px}.tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}.tb-kv-map-config .body md-input-container.cell{margin:0;max-height:40px}.tb-kv-map-config .body .md-button{margin:0}
 | 
			
		||||
/*# sourceMappingURL=rulenode-core-config.css.map*/
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -46,6 +46,7 @@ export default function RelationFilters($compile, $templateCache) {
 | 
			
		||||
        ngModelCtrl.$render = function () {
 | 
			
		||||
            if (ngModelCtrl.$viewValue) {
 | 
			
		||||
                var value = ngModelCtrl.$viewValue;
 | 
			
		||||
                scope.relationFilters.length = 0;
 | 
			
		||||
                value.forEach(function (filter) {
 | 
			
		||||
                    scope.relationFilters.push(filter);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user