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 " +
|
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 " +
|
||||||
"<code>metadata.cs.temperature</code> or <code>metadata.shared.limit</code> " +
|
"<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 {
|
public class TbGetAttributesNode implements TbNode {
|
||||||
|
|
||||||
private TbGetAttributesNodeConfiguration config;
|
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",
|
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 " +
|
||||||
"<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> {
|
public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -16,18 +16,19 @@
|
|||||||
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.rule.engine.data.RelationsQuery;
|
||||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
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 org.thingsboard.server.common.data.relation.EntityTypeFilter;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfiguration {
|
public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfiguration {
|
||||||
|
|
||||||
private String relationType;
|
private RelationsQuery relationsQuery;
|
||||||
private EntitySearchDirection direction;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TbGetRelatedAttrNodeConfiguration defaultConfiguration() {
|
public TbGetRelatedAttrNodeConfiguration defaultConfiguration() {
|
||||||
@ -36,8 +37,14 @@ public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfig
|
|||||||
attrMapping.putIfAbsent("temperature", "tempo");
|
attrMapping.putIfAbsent("temperature", "tempo");
|
||||||
configuration.setAttrMapping(attrMapping);
|
configuration.setAttrMapping(attrMapping);
|
||||||
configuration.setTelemetry(true);
|
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;
|
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 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. " +
|
"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 " +
|
||||||
"<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> {
|
public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> {
|
||||||
|
|
||||||
private TbGetRelatedAttrNodeConfiguration config;
|
private TbGetRelatedAttrNodeConfiguration config;
|
||||||
@ -45,6 +48,6 @@ public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ListenableFuture<EntityId> findEntityAsync(TbContext ctx, EntityId originator) {
|
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",
|
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 " +
|
||||||
"<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> {
|
public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -68,7 +68,7 @@ public class TbChangeOriginatorNode extends TbAbstractTransformNode {
|
|||||||
case TENANT_SOURCE:
|
case TENANT_SOURCE:
|
||||||
return EntitiesTenantIdAsyncLoader.findEntityIdAsync(ctx, original);
|
return EntitiesTenantIdAsyncLoader.findEntityIdAsync(ctx, original);
|
||||||
case RELATED_SOURCE:
|
case RELATED_SOURCE:
|
||||||
return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, original, config.getDirection(), config.getRelationType());
|
return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, original, config.getRelationsQuery());
|
||||||
default:
|
default:
|
||||||
return Futures.immediateFailedFuture(new IllegalStateException("Unexpected originator source " + config.getOriginatorSource()));
|
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.getOriginatorSource().equals(RELATED_SOURCE)) {
|
||||||
if (conf.getDirection() == null || StringUtils.isBlank(conf.getRelationType())) {
|
if (conf.getRelationsQuery() == null) {
|
||||||
log.error("Related source for TbChangeOriginatorNode should have direction and relationType. Actual [{}] [{}]",
|
log.error("Related source for TbChangeOriginatorNode should have relations query. Actual [{}]",
|
||||||
conf.getDirection(), conf.getRelationType());
|
conf.getRelationsQuery());
|
||||||
throw new IllegalArgumentException("Wrong config for RElated Source in TbChangeOriginatorNode" + conf.getOriginatorSource());
|
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 lombok.Data;
|
||||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
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.EntityRelation;
|
||||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
||||||
|
import org.thingsboard.server.common.data.relation.EntityTypeFilter;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TbChangeOriginatorNodeConfiguration extends TbTransformNodeConfiguration implements NodeConfiguration {
|
public class TbChangeOriginatorNodeConfiguration extends TbTransformNodeConfiguration implements NodeConfiguration {
|
||||||
|
|
||||||
private String originatorSource;
|
private String originatorSource;
|
||||||
private EntitySearchDirection direction;
|
|
||||||
private String relationType;
|
private RelationsQuery relationsQuery;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TbChangeOriginatorNodeConfiguration defaultConfiguration() {
|
public TbChangeOriginatorNodeConfiguration defaultConfiguration() {
|
||||||
TbChangeOriginatorNodeConfiguration configuration = new TbChangeOriginatorNodeConfiguration();
|
TbChangeOriginatorNodeConfiguration configuration = new TbChangeOriginatorNodeConfiguration();
|
||||||
configuration.setOriginatorSource(TbChangeOriginatorNode.CUSTOMER_SOURCE);
|
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);
|
configuration.setStartNewChain(false);
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,32 +20,41 @@ import com.google.common.util.concurrent.Futures;
|
|||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.thingsboard.rule.engine.api.TbContext;
|
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.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
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.EntitySearchDirection;
|
||||||
|
import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
|
||||||
import org.thingsboard.server.dao.relation.RelationService;
|
import org.thingsboard.server.dao.relation.RelationService;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.thingsboard.server.common.data.relation.RelationTypeGroup.COMMON;
|
|
||||||
|
|
||||||
public class EntitiesRelatedEntityIdAsyncLoader {
|
public class EntitiesRelatedEntityIdAsyncLoader {
|
||||||
|
|
||||||
public static ListenableFuture<EntityId> findEntityAsync(TbContext ctx, EntityId originator,
|
public static ListenableFuture<EntityId> findEntityAsync(TbContext ctx, EntityId originator,
|
||||||
EntitySearchDirection direction, String relationType) {
|
RelationsQuery relationsQuery) {
|
||||||
RelationService relationService = ctx.getRelationService();
|
RelationService relationService = ctx.getRelationService();
|
||||||
if (direction == EntitySearchDirection.FROM) {
|
EntityRelationsQuery query = buildQuery(originator, relationsQuery);
|
||||||
ListenableFuture<List<EntityRelation>> asyncRelation = relationService.findByFromAndTypeAsync(originator, relationType, COMMON);
|
ListenableFuture<List<EntityRelation>> asyncRelation = relationService.findByQuery(query);
|
||||||
|
if (relationsQuery.getDirection() == EntitySearchDirection.FROM) {
|
||||||
return Futures.transform(asyncRelation, (AsyncFunction<? super List<EntityRelation>, EntityId>)
|
return Futures.transform(asyncRelation, (AsyncFunction<? super List<EntityRelation>, EntityId>)
|
||||||
r -> CollectionUtils.isNotEmpty(r) ? Futures.immediateFuture(r.get(0).getTo())
|
r -> CollectionUtils.isNotEmpty(r) ? Futures.immediateFuture(r.get(0).getTo())
|
||||||
: Futures.immediateFailedFuture(new IllegalStateException("Relation not found")));
|
: Futures.immediateFailedFuture(new IllegalStateException("Relation not found")));
|
||||||
} else if (direction == EntitySearchDirection.TO) {
|
} else if (relationsQuery.getDirection() == EntitySearchDirection.TO) {
|
||||||
ListenableFuture<List<EntityRelation>> asyncRelation = relationService.findByToAndTypeAsync(originator, relationType, COMMON);
|
|
||||||
return Futures.transform(asyncRelation, (AsyncFunction<? super List<EntityRelation>, EntityId>)
|
return Futures.transform(asyncRelation, (AsyncFunction<? super List<EntityRelation>, EntityId>)
|
||||||
r -> CollectionUtils.isNotEmpty(r) ? Futures.immediateFuture(r.get(0).getFrom())
|
r -> CollectionUtils.isNotEmpty(r) ? Futures.immediateFuture(r.get(0).getFrom())
|
||||||
: Futures.immediateFailedFuture(new IllegalStateException("Relation not found")));
|
: Futures.immediateFailedFuture(new IllegalStateException("Relation not found")));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Futures.immediateFailedFuture(new IllegalStateException("Unknown direction"));
|
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*/
|
/*# 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 () {
|
ngModelCtrl.$render = function () {
|
||||||
if (ngModelCtrl.$viewValue) {
|
if (ngModelCtrl.$viewValue) {
|
||||||
var value = ngModelCtrl.$viewValue;
|
var value = ngModelCtrl.$viewValue;
|
||||||
|
scope.relationFilters.length = 0;
|
||||||
value.forEach(function (filter) {
|
value.forEach(function (filter) {
|
||||||
scope.relationFilters.push(filter);
|
scope.relationFilters.push(filter);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user