diff --git a/application/pom.xml b/application/pom.xml index 3693fe6dbe..96c9ab7b39 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -286,7 +286,6 @@ com.jayway.jsonpath json-path - test com.jayway.jsonpath diff --git a/application/src/main/data/upgrade/3.4.1/schema_update.sql b/application/src/main/data/upgrade/3.4.1/schema_update.sql new file mode 100644 index 0000000000..79cde8167f --- /dev/null +++ b/application/src/main/data/upgrade/3.4.1/schema_update.sql @@ -0,0 +1,74 @@ +-- +-- Copyright © 2016-2022 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. +-- + +DO +$$ + DECLARE table_partition RECORD; + BEGIN + -- in case of running the upgrade script a second time: + IF NOT (SELECT exists(SELECT FROM pg_tables WHERE tablename = 'old_audit_log')) THEN + ALTER TABLE audit_log RENAME TO old_audit_log; + ALTER INDEX IF EXISTS idx_audit_log_tenant_id_and_created_time RENAME TO idx_old_audit_log_tenant_id_and_created_time; + + FOR table_partition IN SELECT tablename AS name, split_part(tablename, '_', 3) AS partition_ts + FROM pg_tables WHERE tablename LIKE 'audit_log_%' + LOOP + EXECUTE format('ALTER TABLE %s RENAME TO old_audit_log_%s', table_partition.name, table_partition.partition_ts); + END LOOP; + ELSE + RAISE NOTICE 'Table old_audit_log already exists, leaving as is'; + END IF; + END; +$$; + +CREATE TABLE IF NOT EXISTS audit_log ( + id uuid NOT NULL, + created_time bigint NOT NULL, + tenant_id uuid, + customer_id uuid, + entity_id uuid, + entity_type varchar(255), + entity_name varchar(255), + user_id uuid, + user_name varchar(255), + action_type varchar(255), + action_data varchar(1000000), + action_status varchar(255), + action_failure_details varchar(1000000) +) PARTITION BY RANGE (created_time); +CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time DESC); + +CREATE OR REPLACE PROCEDURE migrate_audit_logs(IN start_time_ms BIGINT, IN end_time_ms BIGINT, IN partition_size_ms BIGINT) + LANGUAGE plpgsql AS +$$ +DECLARE + p RECORD; + partition_end_ts BIGINT; +BEGIN + FOR p IN SELECT DISTINCT (created_time - created_time % partition_size_ms) AS partition_ts FROM old_audit_log + WHERE created_time >= start_time_ms AND created_time < end_time_ms + LOOP + partition_end_ts = p.partition_ts + partition_size_ms; + RAISE NOTICE '[audit_log] Partition to create : [%-%]', p.partition_ts, partition_end_ts; + EXECUTE format('CREATE TABLE IF NOT EXISTS audit_log_%s PARTITION OF audit_log ' || + 'FOR VALUES FROM ( %s ) TO ( %s )', p.partition_ts, p.partition_ts, partition_end_ts); + END LOOP; + + INSERT INTO audit_log + SELECT * FROM old_audit_log + WHERE created_time >= start_time_ms AND created_time < end_time_ms; +END; +$$; diff --git a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java index 2817b1e359..eeb6d8e82e 100644 --- a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java @@ -36,7 +36,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.aware.TenantAwareMsg; -import org.thingsboard.server.common.msg.edge.EdgeEventUpdateMsg; +import org.thingsboard.server.common.msg.edge.EdgeSessionMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; import org.thingsboard.server.common.msg.queue.RuleEngineException; @@ -105,7 +105,9 @@ public class AppActor extends ContextAwareActor { onToDeviceActorMsg((TenantAwareMsg) msg, true); break; case EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG: - onToTenantActorMsg((EdgeEventUpdateMsg) msg); + case EDGE_SYNC_REQUEST_TO_EDGE_SESSION_MSG: + case EDGE_SYNC_RESPONSE_FROM_EDGE_SESSION_MSG: + onToEdgeSessionMsg((EdgeSessionMsg) msg); break; case SESSION_TIMEOUT_MSG: ctx.broadcastToChildrenByType(msg, EntityType.TENANT); @@ -193,7 +195,7 @@ public class AppActor extends ContextAwareActor { () -> new TenantActor.ActorCreator(systemContext, tenantId)); } - private void onToTenantActorMsg(EdgeEventUpdateMsg msg) { + private void onToEdgeSessionMsg(EdgeSessionMsg msg) { TbActorRef target = null; if (ModelConstants.SYSTEM_TENANT.equals(msg.getTenantId())) { log.warn("Message has system tenant id: {}", msg); @@ -203,7 +205,7 @@ public class AppActor extends ContextAwareActor { if (target != null) { target.tellWithHighPriority(msg); } else { - log.debug("[{}] Invalid edge event update msg: {}", msg.getTenantId(), msg); + log.debug("[{}] Invalid edge session msg: {}", msg.getTenantId(), msg); } } diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 239466fe81..3eec2e942b 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -17,8 +17,11 @@ package org.thingsboard.server.actors.ruleChain; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import io.netty.channel.EventLoopGroup; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ListeningExecutor; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.RuleEngineAlarmService; @@ -40,6 +43,7 @@ import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.HasRuleEngineProfile; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.alarm.Alarm; @@ -53,6 +57,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleNode; @@ -89,6 +94,7 @@ import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; import java.util.Collections; +import java.util.List; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -331,58 +337,62 @@ class DefaultTbContext implements TbContext { } public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) { - RuleChainId ruleChainId = null; - String queueName = null; + DeviceProfile deviceProfile = null; if (device.getDeviceProfileId() != null) { - DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId()); - if (deviceProfile == null) { - log.warn("[{}] Device profile is null!", device.getDeviceProfileId()); - } else { - ruleChainId = deviceProfile.getDefaultRuleChainId(); - queueName = deviceProfile.getDefaultQueueName(); - } + deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId()); } - return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, queueName, ruleChainId); + return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, deviceProfile); } public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) { - RuleChainId ruleChainId = null; - String queueName = null; + AssetProfile assetProfile = null; if (asset.getAssetProfileId() != null) { - AssetProfile assetProfile = mainCtx.getAssetProfileCache().find(asset.getAssetProfileId()); - if (assetProfile == null) { - log.warn("[{}] Asset profile is null!", asset.getAssetProfileId()); - } else { - ruleChainId = assetProfile.getDefaultRuleChainId(); - queueName = assetProfile.getDefaultQueueName(); - } + assetProfile = mainCtx.getAssetProfileCache().find(asset.getAssetProfileId()); } - return entityActionMsg(asset, asset.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, queueName, ruleChainId); + return entityActionMsg(asset, asset.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, assetProfile); } public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) { - RuleChainId ruleChainId = null; - String queueName = null; + HasRuleEngineProfile profile = null; if (EntityType.DEVICE.equals(alarm.getOriginator().getEntityType())) { DeviceId deviceId = new DeviceId(alarm.getOriginator().getId()); - DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId); - if (deviceProfile == null) { - log.warn("[{}] Device profile is null!", deviceId); - } else { - ruleChainId = deviceProfile.getDefaultRuleChainId(); - queueName = deviceProfile.getDefaultQueueName(); - } + profile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId); } else if (EntityType.ASSET.equals(alarm.getOriginator().getEntityType())) { AssetId assetId = new AssetId(alarm.getOriginator().getId()); - AssetProfile assetProfile = mainCtx.getAssetProfileCache().get(getTenantId(), assetId); - if (assetProfile == null) { - log.warn("[{}] Asset profile is null!", assetId); - } else { - ruleChainId = assetProfile.getDefaultRuleChainId(); - queueName = assetProfile.getDefaultQueueName(); - } + profile = mainCtx.getAssetProfileCache().get(getTenantId(), assetId); + } + return entityActionMsg(alarm, alarm.getOriginator(), ruleNodeId, action, profile); + } + + public TbMsg attributesUpdatedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List attributes) { + ObjectNode entityNode = JacksonUtil.newObjectNode(); + if (attributes != null) { + attributes.forEach(attributeKvEntry -> JacksonUtil.addKvEntry(entityNode, attributeKvEntry)); } - return entityActionMsg(alarm, alarm.getId(), ruleNodeId, action, queueName, ruleChainId); + return attributesActionMsg(originator, ruleNodeId, scope, DataConstants.ATTRIBUTES_UPDATED, JacksonUtil.toString(entityNode)); + } + + public TbMsg attributesDeletedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List keys) { + ObjectNode entityNode = JacksonUtil.newObjectNode(); + ArrayNode attrsArrayNode = entityNode.putArray("attributes"); + if (keys != null) { + keys.forEach(attrsArrayNode::add); + } + return attributesActionMsg(originator, ruleNodeId, scope, DataConstants.ATTRIBUTES_DELETED, JacksonUtil.toString(entityNode)); + } + + private TbMsg attributesActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, String action, String msgData) { + TbMsgMetaData tbMsgMetaData = getActionMetaData(ruleNodeId); + tbMsgMetaData.putValue("scope", scope); + HasRuleEngineProfile profile = null; + if (EntityType.DEVICE.equals(originator.getEntityType())) { + DeviceId deviceId = new DeviceId(originator.getId()); + profile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId); + } else if (EntityType.ASSET.equals(originator.getEntityType())) { + AssetId assetId = new AssetId(originator.getId()); + profile = mainCtx.getAssetProfileCache().get(getTenantId(), assetId); + } + return entityActionMsg(originator, tbMsgMetaData, msgData, action, profile); } @Override @@ -391,17 +401,27 @@ class DefaultTbContext implements TbContext { } public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action) { - return entityActionMsg(entity, id, ruleNodeId, action, null, null); + return entityActionMsg(entity, id, ruleNodeId, action, null); } - public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, String queueName, RuleChainId ruleChainId) { + public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, K profile) { try { - return TbMsg.newMsg(queueName, action, id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity)), ruleChainId, null); + return entityActionMsg(id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity)), action, profile); } catch (JsonProcessingException | IllegalArgumentException e) { throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " " + action + " msg: " + e); } } + private TbMsg entityActionMsg(I id, TbMsgMetaData msgMetaData, String msgData, String action, K profile) { + String defaultQueueName = null; + RuleChainId defaultRuleChainId = null; + if (profile != null) { + defaultQueueName = profile.getDefaultQueueName(); + defaultRuleChainId = profile.getDefaultRuleChainId(); + } + return TbMsg.newMsg(defaultQueueName, action, id, msgMetaData, msgData, defaultRuleChainId, null); + } + @Override public RuleNodeId getSelfId() { return nodeCtx.getSelf().getId(); diff --git a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java index c22b44d7cf..5718f581ad 100644 --- a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java @@ -47,7 +47,7 @@ import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; -import org.thingsboard.server.common.msg.edge.EdgeEventUpdateMsg; +import org.thingsboard.server.common.msg.edge.EdgeSessionMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; @@ -167,7 +167,9 @@ public class TenantActor extends RuleChainManagerActor { onRuleChainMsg((RuleChainAwareMsg) msg); break; case EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG: - onToEdgeSessionMsg((EdgeEventUpdateMsg) msg); + case EDGE_SYNC_REQUEST_TO_EDGE_SESSION_MSG: + case EDGE_SYNC_RESPONSE_FROM_EDGE_SESSION_MSG: + onToEdgeSessionMsg((EdgeSessionMsg) msg); break; default: return false; @@ -271,9 +273,8 @@ public class TenantActor extends RuleChainManagerActor { () -> new DeviceActorCreator(systemContext, tenantId, deviceId)); } - private void onToEdgeSessionMsg(EdgeEventUpdateMsg msg) { - log.trace("[{}] onToEdgeSessionMsg [{}]", msg.getTenantId(), msg); - systemContext.getEdgeRpcService().onEdgeEvent(tenantId, msg.getEdgeId()); + private void onToEdgeSessionMsg(EdgeSessionMsg msg) { + systemContext.getEdgeRpcService().onToEdgeSessionMsg(tenantId, msg); } private ApiUsageState getApiUsageState() { diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 21edd71ddd..ffc3fcf3cd 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -279,10 +279,7 @@ public abstract class BaseController { protected EdgeService edgeService; @Autowired(required = false) - protected EdgeNotificationService edgeNotificationService; - - @Autowired(required = false) - protected EdgeRpcService edgeGrpcService; + protected EdgeRpcService edgeRpcService; @Autowired protected TbNotificationEntityService notificationEntityService; diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 59c9eb39c1..6a5dd44d0b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -22,6 +22,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -32,6 +33,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.async.DeferredResult; import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; @@ -47,6 +49,8 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.msg.edge.FromEdgeSyncResponse; +import org.thingsboard.server.common.msg.edge.ToEdgeSyncRequest; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; @@ -61,6 +65,7 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; @@ -529,24 +534,35 @@ public class EdgeController extends BaseController { "All entities that are assigned to particular edge are going to be send to remote edge service." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/sync/{edgeId}", method = RequestMethod.POST) - public void syncEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) + public DeferredResult syncEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("edgeId") String strEdgeId) throws ThingsboardException { checkParameter("edgeId", strEdgeId); try { + final DeferredResult response = new DeferredResult<>(); if (isEdgesEnabled()) { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); edgeId = checkNotNull(edgeId); SecurityUser user = getCurrentUser(); TenantId tenantId = user.getTenantId(); - edgeGrpcService.startSyncProcess(tenantId, edgeId); + ToEdgeSyncRequest request = new ToEdgeSyncRequest(UUID.randomUUID(), tenantId, edgeId); + edgeRpcService.processSyncRequest(request, fromEdgeSyncResponse -> reply(response, fromEdgeSyncResponse)); } else { throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL); } + return response; } catch (Exception e) { throw handleException(e); } } + private void reply(DeferredResult response, FromEdgeSyncResponse fromEdgeSyncResponse) { + if (fromEdgeSyncResponse.isSuccess()) { + response.setResult(new ResponseEntity<>(HttpStatus.OK)); + } else { + response.setErrorResult(new ThingsboardException("Edge is not connected", ThingsboardErrorCode.GENERAL)); + } + } + @ApiOperation(value = "Find missing rule chains (findMissingToRelatedRuleChains)", notes = "Returns list of rule chains ids that are not assigned to particular edge, but these rule chains are present in the already assigned rule chains to edge." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index c1f352d8eb..33a6d4bdd1 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -228,6 +228,7 @@ public class ThingsboardInstallService { case "3.4.1": log.info("Upgrading ThingsBoard from version 3.4.1 to 3.4.2 ..."); databaseEntitiesUpgradeService.upgradeDatabase("3.4.1"); + dataUpdateService.updateData("3.4.1"); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; diff --git a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java index 79968187b6..7057f903be 100644 --- a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java +++ b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; @@ -34,9 +35,8 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.DataType; -import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -113,6 +113,15 @@ public class EntityActionService { case UNASSIGNED_FROM_EDGE: msgType = DataConstants.ENTITY_UNASSIGNED_FROM_EDGE; break; + case RELATION_ADD_OR_UPDATE: + msgType = DataConstants.RELATION_ADD_OR_UPDATE; + break; + case RELATION_DELETED: + msgType = DataConstants.RELATION_DELETED; + break; + case RELATIONS_DELETED: + msgType = DataConstants.RELATIONS_DELETED; + break; } if (!StringUtils.isEmpty(msgType)) { try { @@ -170,7 +179,7 @@ public class EntityActionService { metaData.putValue(DataConstants.SCOPE, scope); if (attributes != null) { for (AttributeKvEntry attr : attributes) { - addKvEntry(entityNode, attr); + JacksonUtil.addKvEntry(entityNode, attr); } } } else if (actionType == ActionType.ATTRIBUTES_DELETED) { @@ -195,6 +204,8 @@ public class EntityActionService { } entityNode.put("startTs", extractParameter(Long.class, 1, additionalInfo)); entityNode.put("endTs", extractParameter(Long.class, 2, additionalInfo)); + } else if (ActionType.RELATION_ADD_OR_UPDATE.equals(actionType) || ActionType.RELATION_DELETED.equals(actionType)) { + entityNode = json.valueToTree(extractParameter(EntityRelation.class, 0, additionalInfo)); } } TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode)); @@ -246,27 +257,11 @@ public class EntityActionService { element.put("ts", entry.getKey()); ObjectNode values = element.putObject("values"); for (TsKvEntry tsKvEntry : entry.getValue()) { - addKvEntry(values, tsKvEntry); + JacksonUtil.addKvEntry(values, tsKvEntry); } result.add(element); } } } - private void addKvEntry(ObjectNode entityNode, KvEntry kvEntry) throws Exception { - if (kvEntry.getDataType() == DataType.BOOLEAN) { - kvEntry.getBooleanValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); - } else if (kvEntry.getDataType() == DataType.DOUBLE) { - kvEntry.getDoubleValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); - } else if (kvEntry.getDataType() == DataType.LONG) { - kvEntry.getLongValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); - } else if (kvEntry.getDataType() == DataType.JSON) { - if (kvEntry.getJsonValue().isPresent()) { - entityNode.set(kvEntry.getKey(), json.readTree(kvEntry.getJsonValue().get())); - } - } else { - entityNode.put(kvEntry.getKey(), kvEntry.getValueAsString()); - } - } - } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index c56fcd4ed9..4cb6fcdb0a 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.data.edge.Edge; @@ -34,6 +35,10 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.msg.edge.EdgeEventUpdateMsg; +import org.thingsboard.server.common.msg.edge.EdgeSessionMsg; +import org.thingsboard.server.common.msg.edge.FromEdgeSyncResponse; +import org.thingsboard.server.common.msg.edge.ToEdgeSyncRequest; import org.thingsboard.server.gen.edge.v1.EdgeRpcServiceGrpc; import org.thingsboard.server.gen.edge.v1.RequestMsg; import org.thingsboard.server.gen.edge.v1.ResponseMsg; @@ -59,6 +64,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; @Service @Slf4j @@ -71,6 +77,8 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i private final Map sessionNewEvents = new HashMap<>(); private final ConcurrentMap> sessionEdgeEventChecks = new ConcurrentHashMap<>(); + private final ConcurrentMap> localSyncEdgeRequests = new ConcurrentHashMap<>(); + @Value("${edges.rpc.port}") private int rpcPort; @Value("${edges.rpc.ssl.enabled}") @@ -98,12 +106,17 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i @Autowired private TelemetrySubscriptionService tsSubService; + @Autowired + private TbClusterService clusterService; + private Server server; private ScheduledExecutorService edgeEventProcessingExecutorService; private ScheduledExecutorService sendDownlinkExecutorService; + private ScheduledExecutorService executorService; + @PostConstruct public void init() { log.info("Initializing Edge RPC service!"); @@ -129,8 +142,9 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i log.error("Failed to start Edge RPC server!", e); throw new RuntimeException("Failed to start Edge RPC server!"); } - this.edgeEventProcessingExecutorService = Executors.newScheduledThreadPool(schedulerPoolSize, ThingsBoardThreadFactory.forName("edge-scheduler")); + this.edgeEventProcessingExecutorService = Executors.newScheduledThreadPool(schedulerPoolSize, ThingsBoardThreadFactory.forName("edge-event-check-scheduler")); this.sendDownlinkExecutorService = Executors.newScheduledThreadPool(sendSchedulerPoolSize, ThingsBoardThreadFactory.forName("edge-send-scheduler")); + this.executorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("edge-service")); log.info("Edge RPC service initialized!"); } @@ -153,6 +167,9 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i if (sendDownlinkExecutorService != null) { sendDownlinkExecutorService.shutdownNow(); } + if (executorService != null) { + executorService.shutdownNow(); + } } @Override @@ -160,47 +177,76 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, sendDownlinkExecutorService).getInputStream(); } + @Override + public void onToEdgeSessionMsg(TenantId tenantId, EdgeSessionMsg msg) { + executorService.execute(() -> { + switch (msg.getMsgType()) { + case EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG: + EdgeEventUpdateMsg edgeEventUpdateMsg = (EdgeEventUpdateMsg) msg; + log.trace("[{}] onToEdgeSessionMsg [{}]", edgeEventUpdateMsg.getTenantId(), msg); + onEdgeEvent(tenantId, edgeEventUpdateMsg.getEdgeId()); + break; + case EDGE_SYNC_REQUEST_TO_EDGE_SESSION_MSG: + ToEdgeSyncRequest toEdgeSyncRequest = (ToEdgeSyncRequest) msg; + log.trace("[{}] toEdgeSyncRequest [{}]", toEdgeSyncRequest.getTenantId(), msg); + startSyncProcess(tenantId, toEdgeSyncRequest.getEdgeId(), toEdgeSyncRequest.getId()); + break; + case EDGE_SYNC_RESPONSE_FROM_EDGE_SESSION_MSG: + FromEdgeSyncResponse fromEdgeSyncResponse = (FromEdgeSyncResponse) msg; + log.trace("[{}] fromEdgeSyncResponse [{}]", fromEdgeSyncResponse.getTenantId(), msg); + processSyncResponse(fromEdgeSyncResponse); + break; + } + }); + } + @Override public void updateEdge(TenantId tenantId, Edge edge) { - EdgeGrpcSession session = sessions.get(edge.getId()); - if (session != null && session.isConnected()) { - log.debug("[{}] Updating configuration for edge [{}] [{}]", tenantId, edge.getName(), edge.getId()); - session.onConfigurationUpdate(edge); - } else { - log.debug("[{}] Session doesn't exist for edge [{}] [{}]", tenantId, edge.getName(), edge.getId()); - } + executorService.execute(() -> { + EdgeGrpcSession session = sessions.get(edge.getId()); + if (session != null && session.isConnected()) { + log.debug("[{}] Updating configuration for edge [{}] [{}]", tenantId, edge.getName(), edge.getId()); + session.onConfigurationUpdate(edge); + } else { + log.debug("[{}] Session doesn't exist for edge [{}] [{}]", tenantId, edge.getName(), edge.getId()); + } + }); } @Override public void deleteEdge(TenantId tenantId, EdgeId edgeId) { + executorService.execute(() -> { + EdgeGrpcSession session = sessions.get(edgeId); + if (session != null && session.isConnected()) { + log.info("[{}] Closing and removing session for edge [{}]", tenantId, edgeId); + session.close(); + sessions.remove(edgeId); + final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); + newEventLock.lock(); + try { + sessionNewEvents.remove(edgeId); + } finally { + newEventLock.unlock(); + } + cancelScheduleEdgeEventsCheck(edgeId); + } + }); + } + + private void onEdgeEvent(TenantId tenantId, EdgeId edgeId) { EdgeGrpcSession session = sessions.get(edgeId); if (session != null && session.isConnected()) { - log.info("[{}] Closing and removing session for edge [{}]", tenantId, edgeId); - session.close(); - sessions.remove(edgeId); + log.trace("[{}] onEdgeEvent [{}]", tenantId, edgeId.getId()); final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); newEventLock.lock(); try { - sessionNewEvents.remove(edgeId); + if (Boolean.FALSE.equals(sessionNewEvents.get(edgeId))) { + log.trace("[{}] set session new events flag to true [{}]", tenantId, edgeId.getId()); + sessionNewEvents.put(edgeId, true); + } } finally { newEventLock.unlock(); } - cancelScheduleEdgeEventsCheck(edgeId); - } - } - - @Override - public void onEdgeEvent(TenantId tenantId, EdgeId edgeId) { - log.trace("[{}] onEdgeEvent [{}]", tenantId, edgeId.getId()); - final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); - newEventLock.lock(); - try { - if (Boolean.FALSE.equals(sessionNewEvents.get(edgeId))) { - log.trace("[{}] set session new events flag to true [{}]", tenantId, edgeId.getId()); - sessionNewEvents.put(edgeId, true); - } - } finally { - newEventLock.unlock(); } } @@ -220,14 +266,47 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i scheduleEdgeEventsCheck(edgeGrpcSession); } - @Override - public void startSyncProcess(TenantId tenantId, EdgeId edgeId) { + private void startSyncProcess(TenantId tenantId, EdgeId edgeId, UUID requestId) { EdgeGrpcSession session = sessions.get(edgeId); - if (session != null && session.isConnected()) { - session.startSyncProcess(tenantId, edgeId); + if (session != null) { + boolean success = false; + if (session.isConnected()) { + session.startSyncProcess(tenantId, edgeId); + success = true; + } + clusterService.pushEdgeSyncResponseToCore(new FromEdgeSyncResponse(requestId, tenantId, edgeId, success)); + } + } + + @Override + public void processSyncRequest(ToEdgeSyncRequest request, Consumer responseConsumer) { + log.trace("[{}][{}] Processing sync edge request [{}]", request.getTenantId(), request.getId(), request.getEdgeId()); + UUID requestId = request.getId(); + localSyncEdgeRequests.put(requestId, responseConsumer); + clusterService.pushEdgeSyncRequestToCore(request); + scheduleSyncRequestTimeout(request, requestId); + } + + private void scheduleSyncRequestTimeout(ToEdgeSyncRequest request, UUID requestId) { + log.trace("[{}] scheduling sync edge request", requestId); + executorService.schedule(() -> { + log.trace("[{}] checking if sync edge request is not processed...", requestId); + Consumer consumer = localSyncEdgeRequests.remove(requestId); + if (consumer != null) { + log.trace("[{}] timeout for processing sync edge request.", requestId); + consumer.accept(new FromEdgeSyncResponse(requestId, request.getTenantId(), request.getEdgeId(), false)); + } + }, 20, TimeUnit.SECONDS); + } + + private void processSyncResponse(FromEdgeSyncResponse response) { + log.trace("[{}] Received response from sync service: [{}]", response.getId(), response); + UUID requestId = response.getId(); + Consumer consumer = localSyncEdgeRequests.remove(requestId); + if (consumer != null) { + consumer.accept(response); } else { - log.error("[{}] Edge is not connected [{}]", tenantId, edgeId); - throw new RuntimeException("Edge is not connected"); + log.trace("[{}] Unknown or stale sync response received [{}]", requestId, response); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeRpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeRpcService.java index ad65c15235..6c5515337e 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeRpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeRpcService.java @@ -18,14 +18,19 @@ package org.thingsboard.server.service.edge.rpc; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.msg.edge.EdgeSessionMsg; +import org.thingsboard.server.common.msg.edge.FromEdgeSyncResponse; +import org.thingsboard.server.common.msg.edge.ToEdgeSyncRequest; + +import java.util.function.Consumer; public interface EdgeRpcService { + void onToEdgeSessionMsg(TenantId tenantId, EdgeSessionMsg msg); + void updateEdge(TenantId tenantId, Edge edge); void deleteEdge(TenantId tenantId, EdgeId edgeId); - void onEdgeEvent(TenantId tenantId, EdgeId edgeId); - - void startSyncProcess(TenantId tenantId, EdgeId edgeId); + void processSyncRequest(ToEdgeSyncRequest request, Consumer responseConsumer); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java index 018acb7668..de71fa32a3 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java @@ -76,10 +76,12 @@ import org.thingsboard.server.service.edge.rpc.constructor.RuleChainMsgConstruct import org.thingsboard.server.service.edge.rpc.constructor.UserMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.WidgetTypeMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.WidgetsBundleMsgConstructor; +import org.thingsboard.server.service.entitiy.TbNotificationEntityService; import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.profile.TbAssetProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.state.DeviceStateService; +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import java.util.ArrayList; import java.util.List; @@ -91,6 +93,12 @@ public abstract class BaseEdgeProcessor { protected static final int DEFAULT_PAGE_SIZE = 1000; + @Autowired + protected TelemetrySubscriptionService tsSubService; + + @Autowired + protected TbNotificationEntityService notificationEntityService; + @Autowired protected RuleChainService ruleChainService; diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java index f3bb328886..171d5518fc 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEventActionType; @@ -57,6 +58,7 @@ import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.util.JsonUtils; +import org.thingsboard.server.controller.BaseController; import org.thingsboard.server.gen.edge.v1.AttributeDeleteMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.EntityDataProto; @@ -101,7 +103,7 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor { } if (entityData.hasAttributesUpdatedMsg()) { metaData.putValue("scope", entityData.getPostAttributeScope()); - result.add(processAttributesUpdate(tenantId, customerId, entityId, entityData.getAttributesUpdatedMsg(), metaData)); + result.add(processAttributesUpdate(tenantId, entityId, entityData.getAttributesUpdatedMsg(), metaData)); } if (entityData.hasPostTelemetryMsg()) { result.add(processPostTelemetry(tenantId, customerId, entityId, entityData.getPostTelemetryMsg(), metaData)); @@ -224,39 +226,36 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor { return futureToSet; } - private ListenableFuture processAttributesUpdate(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { + private ListenableFuture processAttributesUpdate(TenantId tenantId, + EntityId entityId, + TransportProtos.PostAttributeMsg msg, + TbMsgMetaData metaData) { SettableFuture futureToSet = SettableFuture.create(); JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); - Set attributes = JsonConverter.convertToAttributes(json); - ListenableFuture> future = attributesService.save(tenantId, entityId, metaData.getValue("scope"), new ArrayList<>(attributes)); - Futures.addCallback(future, new FutureCallback<>() { + List attributes = new ArrayList<>(JsonConverter.convertToAttributes(json)); + String scope = metaData.getValue("scope"); + tsSubService.saveAndNotify(tenantId, entityId, scope, attributes, new FutureCallback() { @Override - public void onSuccess(@Nullable List keys) { - var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); - tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { - @Override - public void onSuccess(TbQueueMsgMetadata metadata) { - futureToSet.set(null); - } - - @Override - public void onFailure(Throwable t) { - log.error("Can't process attributes update [{}]", msg, t); - futureToSet.setException(t); - } - }); + public void onSuccess(@Nullable Void tmp) { + logAttributesUpdated(tenantId, entityId, scope, attributes, null); + futureToSet.set(null); } @Override public void onFailure(Throwable t) { log.error("Can't process attributes update [{}]", msg, t); + logAttributesUpdated(tenantId, entityId, scope, attributes, t); futureToSet.setException(t); } - }, dbCallbackExecutorService); + }); return futureToSet; } + private void logAttributesUpdated(TenantId tenantId, EntityId entityId, String scope, List attributes, Throwable e) { + notificationEntityService.logEntityAction(tenantId, entityId, ActionType.ATTRIBUTES_UPDATED, null, + BaseController.toException(e), scope, attributes); + } + private ListenableFuture processAttributeDeleteMsg(TenantId tenantId, EntityId entityId, AttributeDeleteMsg attributeDeleteMsg, String entityType) { SettableFuture futureToSet = SettableFuture.create(); String scope = attributeDeleteMsg.getScope(); diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index c5c81bfc91..092726d0c8 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -15,8 +15,6 @@ */ package org.thingsboard.server.service.install; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -25,10 +23,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntitySubtype; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.TenantProfile; -import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -37,8 +32,6 @@ import org.thingsboard.server.common.data.queue.ProcessingStrategyType; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.queue.SubmitStrategy; import org.thingsboard.server.common.data.queue.SubmitStrategyType; -import org.thingsboard.server.common.data.rule.RuleNode; -import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.asset.AssetProfileService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.dashboard.DashboardService; @@ -63,11 +56,8 @@ import java.sql.SQLException; import java.sql.SQLSyntaxErrorException; import java.sql.SQLWarning; import java.sql.Statement; -import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import static org.thingsboard.server.service.install.DatabaseHelper.ADDITIONAL_INFO; import static org.thingsboard.server.service.install.DatabaseHelper.ASSIGNED_CUSTOMERS; @@ -620,8 +610,8 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService case "3.4.1": try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { log.info("Updating schema ..."); + runSchemaUpdateScript(conn, "3.4.1"); if (isOldSchema(conn, 3004001)) { - try { conn.createStatement().execute("ALTER TABLE asset ADD COLUMN asset_profile_id uuid"); } catch (Exception e) { @@ -669,6 +659,11 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService } } + private void runSchemaUpdateScript(Connection connection, String version) throws Exception { + Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", version, SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, connection); + } + private void loadSql(Path sqlFile, Connection conn) throws Exception { String sql = new String(Files.readAllBytes(sqlFile), Charset.forName("UTF-8")); Statement st = conn.createStatement(); diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index d02f50b37b..a8cf5374a2 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -63,6 +63,7 @@ import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.alarm.AlarmDao; +import org.thingsboard.server.dao.audit.AuditLogDao; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.event.EventService; @@ -138,6 +139,9 @@ public class DefaultDataUpdateService implements DataUpdateService { @Autowired private EventService eventService; + @Autowired + private AuditLogDao auditLogDao; + @Override public void updateData(String fromVersion) throws Exception { switch (fromVersion) { @@ -170,12 +174,22 @@ public class DefaultDataUpdateService implements DataUpdateService { rateLimitsUpdater.updateEntities(); break; case "3.4.0": - String skipEventsMigration = System.getenv("TB_SKIP_EVENTS_MIGRATION"); - if (skipEventsMigration == null || skipEventsMigration.equalsIgnoreCase("false")) { + boolean skipEventsMigration = getEnv("TB_SKIP_EVENTS_MIGRATION", false); + if (!skipEventsMigration) { log.info("Updating data from version 3.4.0 to 3.4.1 ..."); eventService.migrateEvents(); } break; + case "3.4.1": + boolean skipAuditLogsMigration = getEnv("TB_SKIP_AUDIT_LOGS_MIGRATION", false); + if (!skipAuditLogsMigration) { + log.info("Updating data from version 3.4.1 to 3.4.2 ..."); + log.info("Starting audit logs migration. Can be skipped with TB_SKIP_AUDIT_LOGS_MIGRATION env variable set to true"); + auditLogDao.migrateAuditLogs(); + } else { + log.info("Skipping audit logs migration"); + } + break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } @@ -645,4 +659,13 @@ public class DefaultDataUpdateService implements DataUpdateService { return mainQueueConfiguration; } + private boolean getEnv(String name, boolean defaultValue) { + String env = System.getenv(name); + if (env == null) { + return defaultValue; + } else { + return Boolean.parseBoolean(env); + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index ca654ec802..7983a0adcd 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -51,6 +51,8 @@ import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; import org.thingsboard.server.common.msg.edge.EdgeEventUpdateMsg; +import org.thingsboard.server.common.msg.edge.FromEdgeSyncResponse; +import org.thingsboard.server.common.msg.edge.ToEdgeSyncRequest; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; @@ -372,12 +374,32 @@ public class DefaultTbClusterService implements TbClusterService { log.trace("[{}] Processing edge {} event update ", tenantId, edgeId); EdgeEventUpdateMsg msg = new EdgeEventUpdateMsg(tenantId, edgeId); byte[] msgBytes = encodingService.encode(msg); + ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setEdgeEventUpdateMsg(ByteString.copyFrom(msgBytes)).build(); + pushEdgeSyncMsgToCore(edgeId, toCoreMsg); + } + + @Override + public void pushEdgeSyncRequestToCore(ToEdgeSyncRequest toEdgeSyncRequest) { + log.trace("[{}] Processing edge sync request {} ", toEdgeSyncRequest.getTenantId(), toEdgeSyncRequest); + byte[] msgBytes = encodingService.encode(toEdgeSyncRequest); + ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setToEdgeSyncRequestMsg(ByteString.copyFrom(msgBytes)).build(); + pushEdgeSyncMsgToCore(toEdgeSyncRequest.getEdgeId(), toCoreMsg); + } + + @Override + public void pushEdgeSyncResponseToCore(FromEdgeSyncResponse fromEdgeSyncResponse) { + log.trace("[{}] Processing edge sync response {}", fromEdgeSyncResponse.getTenantId(), fromEdgeSyncResponse); + byte[] msgBytes = encodingService.encode(fromEdgeSyncResponse); + ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setFromEdgeSyncResponseMsg(ByteString.copyFrom(msgBytes)).build(); + pushEdgeSyncMsgToCore(fromEdgeSyncResponse.getEdgeId(), toCoreMsg); + } + + private void pushEdgeSyncMsgToCore(EdgeId edgeId, ToCoreNotificationMsg toCoreMsg) { TbQueueProducer> toCoreNfProducer = producerProvider.getTbCoreNotificationsMsgProducer(); Set tbCoreServices = partitionService.getAllServiceIds(ServiceType.TB_CORE); for (String serviceId : tbCoreServices) { TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceId); - ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setEdgeEventUpdateMsg(ByteString.copyFrom(msgBytes)).build(); - toCoreNfProducer.send(tpi, new TbProtoQueueMsg<>(msg.getEdgeId().getId(), toCoreMsg), null); + toCoreNfProducer.send(tpi, new TbProtoQueueMsg<>(edgeId.getId(), toCoreMsg), null); toCoreNfs.incrementAndGet(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index 9cdf3e4aa2..ec58ac1aa9 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -20,8 +20,6 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.event.EventListener; -import org.springframework.core.annotation.Order; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; @@ -77,7 +75,6 @@ import org.thingsboard.server.service.state.DeviceStateService; import org.thingsboard.server.service.subscription.SubscriptionManagerService; import org.thingsboard.server.service.subscription.TbLocalSubscriptionService; import org.thingsboard.server.service.subscription.TbSubscriptionUtils; -import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; import org.thingsboard.server.service.sync.vc.GitVersionControlQueueService; import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; @@ -319,13 +316,12 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService actorMsg = encodingService.decode(toCoreNotification.getEdgeEventUpdateMsg().toByteArray()); - if (actorMsg.isPresent()) { - log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get()); - actorContext.tellWithHighPriority(actorMsg.get()); - } - callback.onSuccess(); + } else if (!toCoreNotification.getEdgeEventUpdateMsg().isEmpty()) { + forwardToAppActor(id, encodingService.decode(toCoreNotification.getEdgeEventUpdateMsg().toByteArray()), callback); + } else if (!toCoreNotification.getToEdgeSyncRequestMsg().isEmpty()) { + forwardToAppActor(id, encodingService.decode(toCoreNotification.getToEdgeSyncRequestMsg().toByteArray()), callback); + } else if (!toCoreNotification.getFromEdgeSyncResponseMsg().isEmpty()) { + forwardToAppActor(id, encodingService.decode(toCoreNotification.getFromEdgeSyncResponseMsg().toByteArray()), callback); } else if (toCoreNotification.hasQueueUpdateMsg()) { TransportProtos.QueueUpdateMsg queue = toCoreNotification.getQueueUpdateMsg(); partitionService.updateQueue(queue); @@ -554,6 +550,14 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService actorMsg, TbCallback callback) { + if (actorMsg.isPresent()) { + log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get()); + actorContext.tell(actorMsg.get()); + } + callback.onSuccess(); + } + private void throwNotHandled(Object msg, TbCallback callback) { log.warn("Message not handled: {}", msg); callback.onFailure(new RuntimeException("Message not handled!")); diff --git a/application/src/main/java/org/thingsboard/server/service/script/AbstractJsInvokeService.java b/application/src/main/java/org/thingsboard/server/service/script/AbstractJsInvokeService.java index eef49ae518..cc46f0a74f 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/AbstractJsInvokeService.java +++ b/application/src/main/java/org/thingsboard/server/service/script/AbstractJsInvokeService.java @@ -15,9 +15,14 @@ */ package org.thingsboard.server.service.script; +import com.google.common.hash.Hashing; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.util.Pair; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.id.CustomerId; @@ -30,20 +35,33 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import static java.lang.String.format; + /** * Created by ashvayka on 26.09.18. */ @Slf4j +@SuppressWarnings("UnstableApiUsage") public abstract class AbstractJsInvokeService implements JsInvokeService { private final TbApiUsageStateService apiUsageStateService; private final TbApiUsageClient apiUsageClient; protected ScheduledExecutorService timeoutExecutorService; - protected Map scriptIdToNameMap = new ConcurrentHashMap<>(); - protected Map disabledFunctions = new ConcurrentHashMap<>(); + + protected final Map> scriptIdToNameAndHashMap = new ConcurrentHashMap<>(); + protected final Map disabledFunctions = new ConcurrentHashMap<>(); + + @Getter + @Value("${js.max_total_args_size:100000}") + private long maxTotalArgsSize; + @Getter + @Value("${js.max_result_size:300000}") + private long maxResultSize; + @Getter + @Value("${js.max_script_body_size:50000}") + private long maxScriptBodySize; protected AbstractJsInvokeService(TbApiUsageStateService apiUsageStateService, TbApiUsageClient apiUsageClient) { this.apiUsageStateService = apiUsageStateService; @@ -65,44 +83,63 @@ public abstract class AbstractJsInvokeService implements JsInvokeService { @Override public ListenableFuture eval(TenantId tenantId, JsScriptType scriptType, String scriptBody, String... argNames) { if (apiUsageStateService.getApiUsageState(tenantId).isJsExecEnabled()) { + if (scriptBodySizeExceeded(scriptBody)) { + return error(format("Script body exceeds maximum allowed size of %s symbols", getMaxScriptBodySize())); + } UUID scriptId = UUID.randomUUID(); - String functionName = "invokeInternal_" + scriptId.toString().replace('-', '_'); + String scriptHash = hash(tenantId, scriptBody); + String functionName = constructFunctionName(scriptId, scriptHash); String jsScript = generateJsScript(scriptType, functionName, scriptBody, argNames); - return doEval(scriptId, functionName, jsScript); + return doEval(scriptId, scriptHash, functionName, jsScript); } else { - return Futures.immediateFailedFuture(new RuntimeException("JS Execution is disabled due to API limits!")); + return error("JS Execution is disabled due to API limits!"); } } + protected String constructFunctionName(UUID scriptId, String scriptHash) { + return "invokeInternal_" + scriptId.toString().replace('-', '_'); + } + @Override - public ListenableFuture invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args) { + public ListenableFuture invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args) { if (apiUsageStateService.getApiUsageState(tenantId).isJsExecEnabled()) { - String functionName = scriptIdToNameMap.get(scriptId); - if (functionName == null) { - return Futures.immediateFailedFuture(new RuntimeException("No compiled script found for scriptId: [" + scriptId + "]!")); + Pair nameAndHash = scriptIdToNameAndHashMap.get(scriptId); + if (nameAndHash == null) { + return error("No compiled script found for scriptId: [" + scriptId + "]!"); } + String functionName = nameAndHash.getFirst(); + String scriptHash = nameAndHash.getSecond(); if (!isDisabled(scriptId)) { + if (argsSizeExceeded(args)) { + return scriptExecutionError(scriptId, format("Script input arguments exceed maximum allowed total args size of %s symbols", getMaxTotalArgsSize())); + } apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.JS_EXEC_COUNT, 1); - return doInvokeFunction(scriptId, functionName, args); + return Futures.transformAsync(doInvokeFunction(scriptId, scriptHash, functionName, args), output -> { + String result = output.toString(); + if (resultSizeExceeded(result)) { + return scriptExecutionError(scriptId, format("Script invocation result exceeds maximum allowed size of %s symbols", getMaxResultSize())); + } + return Futures.immediateFuture(result); + }, MoreExecutors.directExecutor()); } else { String message = "Script invocation is blocked due to maximum error count " + getMaxErrors() + ", scriptId " + scriptId + "!"; log.warn(message); - return Futures.immediateFailedFuture(new RuntimeException(message)); + return error(message); } } else { - return Futures.immediateFailedFuture(new RuntimeException("JS Execution is disabled due to API limits!")); + return error("JS Execution is disabled due to API limits!"); } } @Override public ListenableFuture release(UUID scriptId) { - String functionName = scriptIdToNameMap.get(scriptId); - if (functionName != null) { + Pair nameAndHash = scriptIdToNameAndHashMap.get(scriptId); + if (nameAndHash != null) { try { - scriptIdToNameMap.remove(scriptId); + scriptIdToNameAndHashMap.remove(scriptId); disabledFunctions.remove(scriptId); - doRelease(scriptId, functionName); + doRelease(scriptId, nameAndHash.getSecond(), nameAndHash.getFirst()); } catch (Exception e) { return Futures.immediateFailedFuture(e); } @@ -110,16 +147,24 @@ public abstract class AbstractJsInvokeService implements JsInvokeService { return Futures.immediateFuture(null); } - protected abstract ListenableFuture doEval(UUID scriptId, String functionName, String scriptBody); + protected abstract ListenableFuture doEval(UUID scriptId, String scriptHash, String functionName, String scriptBody); - protected abstract ListenableFuture doInvokeFunction(UUID scriptId, String functionName, Object[] args); + protected abstract ListenableFuture doInvokeFunction(UUID scriptId, String scriptHash, String functionName, Object[] args); - protected abstract void doRelease(UUID scriptId, String functionName) throws Exception; + protected abstract void doRelease(UUID scriptId, String scriptHash, String functionName) throws Exception; protected abstract int getMaxErrors(); protected abstract long getMaxBlacklistDuration(); + protected String hash(TenantId tenantId, String scriptBody) { + return Hashing.murmur3_128().newHasher() + .putLong(tenantId.getId().getMostSignificantBits()) + .putLong(tenantId.getId().getLeastSignificantBits()) + .putUnencodedChars(scriptBody) + .hash().toString(); + } + protected void onScriptExecutionError(UUID scriptId, Throwable t, String scriptBody) { DisableListInfo disableListInfo = disabledFunctions.computeIfAbsent(scriptId, key -> new DisableListInfo()); log.warn("Script has exception and will increment counter {} on disabledFunctions for id {}, exception {}, cause {}, scriptBody {}", @@ -127,6 +172,27 @@ public abstract class AbstractJsInvokeService implements JsInvokeService { disableListInfo.incrementAndGet(); } + private boolean scriptBodySizeExceeded(String scriptBody) { + if (getMaxScriptBodySize() <= 0) return false; + return scriptBody.length() > getMaxScriptBodySize(); + } + + private boolean argsSizeExceeded(Object[] args) { + if (getMaxTotalArgsSize() <= 0) return false; + long totalArgsSize = 0; + for (Object arg : args) { + if (arg instanceof CharSequence) { + totalArgsSize += ((CharSequence) arg).length(); + } + } + return totalArgsSize > getMaxTotalArgsSize(); + } + + private boolean resultSizeExceeded(String result) { + if (getMaxResultSize() <= 0) return false; + return result.length() > getMaxResultSize(); + } + private String generateJsScript(JsScriptType scriptType, String functionName, String scriptBody, String... argNames) { if (scriptType == JsScriptType.RULE_NODE_SCRIPT) { return RuleNodeScriptFactory.generateRuleNodeScript(functionName, scriptBody, argNames); @@ -148,6 +214,16 @@ public abstract class AbstractJsInvokeService implements JsInvokeService { } } + private ListenableFuture error(String message) { + return Futures.immediateFailedFuture(new RuntimeException(message)); + } + + private ListenableFuture scriptExecutionError(UUID scriptId, String errorMsg) { + RuntimeException error = new RuntimeException(errorMsg); + onScriptExecutionError(scriptId, error, null); + return Futures.immediateFailedFuture(error); + } + private class DisableListInfo { private final AtomicInteger counter; private long expirationTime; diff --git a/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java b/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java index d731ef1536..4b19bf9020 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java +++ b/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java @@ -24,6 +24,7 @@ import delight.nashornsandbox.NashornSandboxes; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.util.Pair; import org.springframework.scheduling.annotation.Scheduled; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.queue.usagestats.TbApiUsageClient; @@ -38,7 +39,6 @@ import javax.script.ScriptException; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; @@ -121,7 +121,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer protected abstract long getMaxCpuTime(); @Override - protected ListenableFuture doEval(UUID scriptId, String functionName, String jsScript) { + protected ListenableFuture doEval(UUID scriptId, String scriptHash, String functionName, String jsScript) { jsPushedMsgs.incrementAndGet(); ListenableFuture result = jsExecutor.executeAsync(() -> { try { @@ -135,7 +135,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer } finally { evalLock.unlock(); } - scriptIdToNameMap.put(scriptId, functionName); + scriptIdToNameAndHashMap.put(scriptId, Pair.of(functionName, scriptHash)); return scriptId; } catch (Exception e) { log.debug("Failed to compile JS script: {}", e.getMessage(), e); @@ -150,7 +150,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer } @Override - protected ListenableFuture doInvokeFunction(UUID scriptId, String functionName, Object[] args) { + protected ListenableFuture doInvokeFunction(UUID scriptId, String scriptHash, String functionName, Object[] args) { jsPushedMsgs.incrementAndGet(); ListenableFuture result = jsExecutor.executeAsync(() -> { try { @@ -174,7 +174,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer return result; } - protected void doRelease(UUID scriptId, String functionName) throws ScriptException { + protected void doRelease(UUID scriptId, String scriptHash, String functionName) throws ScriptException { if (useJsSandbox()) { sandbox.eval(functionName + " = undefined;"); } else { diff --git a/application/src/main/java/org/thingsboard/server/service/script/JsInvokeService.java b/application/src/main/java/org/thingsboard/server/service/script/JsInvokeService.java index 3e5d014bef..f9af2f83e4 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/JsInvokeService.java +++ b/application/src/main/java/org/thingsboard/server/service/script/JsInvokeService.java @@ -25,7 +25,7 @@ public interface JsInvokeService { ListenableFuture eval(TenantId tenantId, JsScriptType scriptType, String scriptBody, String... argNames); - ListenableFuture invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args); + ListenableFuture invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args); ListenableFuture release(UUID scriptId); diff --git a/application/src/main/java/org/thingsboard/server/service/script/NashornJsInvokeService.java b/application/src/main/java/org/thingsboard/server/service/script/NashornJsInvokeService.java index 5d64017f33..4b9e5dea57 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/NashornJsInvokeService.java +++ b/application/src/main/java/org/thingsboard/server/service/script/NashornJsInvokeService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.script; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -32,12 +33,15 @@ public class NashornJsInvokeService extends AbstractNashornJsInvokeService { @Value("${js.local.use_js_sandbox}") private boolean useJsSandbox; + @Getter @Value("${js.local.monitor_thread_pool_size}") private int monitorThreadPoolSize; + @Getter @Value("${js.local.max_cpu_time}") private long maxCpuTime; + @Getter @Value("${js.local.max_errors}") private int maxErrors; @@ -53,21 +57,6 @@ public class NashornJsInvokeService extends AbstractNashornJsInvokeService { return useJsSandbox; } - @Override - protected int getMonitorThreadPoolSize() { - return monitorThreadPoolSize; - } - - @Override - protected long getMaxCpuTime() { - return maxCpuTime; - } - - @Override - protected int getMaxErrors() { - return maxErrors; - } - @Override protected long getMaxBlacklistDuration() { return TimeUnit.SECONDS.toMillis(maxBlackListDurationSec); diff --git a/application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java b/application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java index 86b364afd4..328fc5ebb4 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java +++ b/application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java @@ -18,16 +18,19 @@ package org.thingsboard.server.service.script; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.data.util.Pair; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.util.StopWatch; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.gen.js.JsInvokeProtos.JsInvokeErrorCode; import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -45,6 +48,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; @Slf4j @ConditionalOnExpression("'${js.evaluator:null}'=='remote' && ('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core' || '${service.type:null}'=='tb-rule-engine')") @@ -98,9 +103,10 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { } @Autowired - private TbQueueRequestTemplate, TbProtoQueueMsg> requestTemplate; + protected TbQueueRequestTemplate, TbProtoQueueMsg> requestTemplate; - private Map scriptIdToBodysMap = new ConcurrentHashMap<>(); + protected final Map scriptHashToBodysMap = new ConcurrentHashMap<>(); + private final Lock scriptsLock = new ReentrantLock(); @PostConstruct public void init() { @@ -117,10 +123,9 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { } @Override - protected ListenableFuture doEval(UUID scriptId, String functionName, String scriptBody) { + protected ListenableFuture doEval(UUID scriptId, String scriptHash, String functionName, String scriptBody) { JsInvokeProtos.JsCompileRequest jsRequest = JsInvokeProtos.JsCompileRequest.newBuilder() - .setScriptIdMSB(scriptId.getMostSignificantBits()) - .setScriptIdLSB(scriptId.getLeastSignificantBits()) + .setScriptHash(scriptHash) .setFunctionName(functionName) .setScriptBody(scriptBody).build(); @@ -128,74 +133,100 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { .setCompileRequest(jsRequest) .build(); - log.trace("Post compile request for scriptId [{}]", scriptId); - ListenableFuture> future = requestTemplate.send(new TbProtoJsQueueMsg<>(UUID.randomUUID(), jsRequestWrapper)); - if (maxEvalRequestsTimeout > 0) { - future = Futures.withTimeout(future, maxEvalRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); - } - queuePushedMsgs.incrementAndGet(); - Futures.addCallback(future, new FutureCallback>() { - @Override - public void onSuccess(@Nullable TbProtoQueueMsg result) { - queueEvalMsgs.incrementAndGet(); - } - - @Override - public void onFailure(Throwable t) { - if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) { - queueTimeoutMsgs.incrementAndGet(); - } - queueFailedMsgs.incrementAndGet(); - } - }, callbackExecutor); + log.trace("Post compile request for scriptId [{}] (hash: {})", scriptId, scriptHash); + ListenableFuture> future = sendJsRequest(UUID.randomUUID(), jsRequestWrapper, maxEvalRequestsTimeout, queueEvalMsgs); return Futures.transform(future, response -> { JsInvokeProtos.JsCompileResponse compilationResult = response.getValue().getCompileResponse(); - UUID compiledScriptId = new UUID(compilationResult.getScriptIdMSB(), compilationResult.getScriptIdLSB()); if (compilationResult.getSuccess()) { - scriptIdToNameMap.put(scriptId, functionName); - scriptIdToBodysMap.put(scriptId, scriptBody); - return compiledScriptId; + scriptsLock.lock(); + try { + scriptIdToNameAndHashMap.put(scriptId, Pair.of(functionName, scriptHash)); + scriptHashToBodysMap.put(scriptHash, scriptBody); + } finally { + scriptsLock.unlock(); + } + return scriptId; } else { - log.debug("[{}] Failed to compile script due to [{}]: {}", compiledScriptId, compilationResult.getErrorCode().name(), compilationResult.getErrorDetails()); + log.debug("[{}] (hash: {}) Failed to compile script due to [{}]: {}", scriptId, compilationResult.getScriptHash(), + compilationResult.getErrorCode().name(), compilationResult.getErrorDetails()); throw new RuntimeException(compilationResult.getErrorDetails()); } }, callbackExecutor); } @Override - protected ListenableFuture doInvokeFunction(UUID scriptId, String functionName, Object[] args) { - log.trace("doInvokeFunction js-request for uuid {} with timeout {}ms", scriptId, maxRequestsTimeout); - final String scriptBody = scriptIdToBodysMap.get(scriptId); - if (scriptBody == null) { - return Futures.immediateFailedFuture(new RuntimeException("No script body found for scriptId: [" + scriptId + "]!")); - } - JsInvokeProtos.JsInvokeRequest.Builder jsRequestBuilder = JsInvokeProtos.JsInvokeRequest.newBuilder() - .setScriptIdMSB(scriptId.getMostSignificantBits()) - .setScriptIdLSB(scriptId.getLeastSignificantBits()) - .setFunctionName(functionName) - .setTimeout((int) maxExecRequestsTimeout) - .setScriptBody(scriptBody); + protected String constructFunctionName(UUID scriptId, String scriptHash) { + return "invokeInternal_" + scriptHash; + } - for (Object arg : args) { - jsRequestBuilder.addArgs(arg.toString()); + @Override + protected ListenableFuture doInvokeFunction(UUID scriptId, String scriptHash, String functionName, Object[] args) { + log.trace("doInvokeFunction js-request for uuid {} with timeout {}ms", scriptHash, maxRequestsTimeout); + String scriptBody = scriptHashToBodysMap.get(scriptHash); + if (scriptBody == null) { + return Futures.immediateFailedFuture(new RuntimeException("No script body found for script hash [" + scriptHash + "] (script id: [" + scriptId + "])")); } - - JsInvokeProtos.RemoteJsRequest jsRequestWrapper = JsInvokeProtos.RemoteJsRequest.newBuilder() - .setInvokeRequest(jsRequestBuilder.build()) - .build(); + JsInvokeProtos.RemoteJsRequest jsRequestWrapper = buildJsInvokeRequest(scriptHash, functionName, args, false, null); StopWatch stopWatch = new StopWatch(); stopWatch.start(); - ListenableFuture> future = requestTemplate.send(new TbProtoJsQueueMsg<>(UUID.randomUUID(), jsRequestWrapper)); + UUID requestKey = UUID.randomUUID(); + ListenableFuture> future = sendJsRequest(requestKey, jsRequestWrapper, maxRequestsTimeout, queueInvokeMsgs); + return Futures.transformAsync(future, response -> { + stopWatch.stop(); + log.trace("doInvokeFunction js-response took {}ms for uuid {}", stopWatch.getTotalTimeMillis(), response.getKey()); + JsInvokeProtos.JsInvokeResponse invokeResult = response.getValue().getInvokeResponse(); + if (invokeResult.getSuccess()) { + return Futures.immediateFuture(invokeResult.getResult()); + } else { + return handleInvokeError(requestKey, scriptId, scriptHash, invokeResult.getErrorCode(), + invokeResult.getErrorDetails(), functionName, args, scriptBody); + } + }, callbackExecutor); + } + + private ListenableFuture handleInvokeError(UUID requestKey, UUID scriptId, String scriptHash, + JsInvokeErrorCode errorCode, String errorDetails, + String functionName, Object[] args, String scriptBody) { + log.debug("[{}] Failed to invoke function due to [{}]: {}", scriptId, errorCode.name(), errorDetails); + RuntimeException e = new RuntimeException(errorDetails); + if (JsInvokeErrorCode.TIMEOUT_ERROR.equals(errorCode)) { + onScriptExecutionError(scriptId, e, scriptBody); + queueTimeoutMsgs.incrementAndGet(); + } else if (JsInvokeErrorCode.COMPILATION_ERROR.equals(errorCode)) { + onScriptExecutionError(scriptId, e, scriptBody); + } else if (JsInvokeErrorCode.NOT_FOUND_ERROR.equals(errorCode)) { + log.debug("[{}] Remote JS executor couldn't find the script", scriptId); + if (scriptBody != null) { + JsInvokeProtos.RemoteJsRequest invokeRequestWithScriptBody = buildJsInvokeRequest(scriptHash, functionName, args, true, scriptBody); + log.debug("[{}] Sending invoke request again with script body", scriptId); + return Futures.transformAsync(sendJsRequest(requestKey, invokeRequestWithScriptBody, maxRequestsTimeout, queueInvokeMsgs), r -> { + JsInvokeProtos.JsInvokeResponse result = r.getValue().getInvokeResponse(); + if (result.getSuccess()) { + return Futures.immediateFuture(result.getResult()); + } else { + return handleInvokeError(requestKey, scriptId, scriptHash, result.getErrorCode(), + result.getErrorDetails(), functionName, args, null); + } + }, MoreExecutors.directExecutor()); + } + } + queueFailedMsgs.incrementAndGet(); + return Futures.immediateFailedFuture(e); + } + + private ListenableFuture> sendJsRequest(UUID requestKey, JsInvokeProtos.RemoteJsRequest jsRequestWrapper, + long maxRequestsTimeout, AtomicInteger msgsCounter) { + ListenableFuture> future = requestTemplate.send(new TbProtoJsQueueMsg<>(requestKey, jsRequestWrapper)); if (maxRequestsTimeout > 0) { future = Futures.withTimeout(future, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); } queuePushedMsgs.incrementAndGet(); - Futures.addCallback(future, new FutureCallback>() { + Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(@Nullable TbProtoQueueMsg result) { - queueInvokeMsgs.incrementAndGet(); + msgsCounter.incrementAndGet(); } @Override @@ -206,32 +237,32 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { queueFailedMsgs.incrementAndGet(); } }, callbackExecutor); - return Futures.transform(future, response -> { - stopWatch.stop(); - log.trace("doInvokeFunction js-response took {}ms for uuid {}", stopWatch.getTotalTimeMillis(), response.getKey()); - JsInvokeProtos.JsInvokeResponse invokeResult = response.getValue().getInvokeResponse(); - if (invokeResult.getSuccess()) { - return invokeResult.getResult(); - } else { - final RuntimeException e = new RuntimeException(invokeResult.getErrorDetails()); - if (JsInvokeProtos.JsInvokeErrorCode.TIMEOUT_ERROR.equals(invokeResult.getErrorCode())) { - onScriptExecutionError(scriptId, e, scriptBody); - queueTimeoutMsgs.incrementAndGet(); - } else if (JsInvokeProtos.JsInvokeErrorCode.COMPILATION_ERROR.equals(invokeResult.getErrorCode())) { - onScriptExecutionError(scriptId, e, scriptBody); - } - queueFailedMsgs.incrementAndGet(); - log.debug("[{}] Failed to invoke function due to [{}]: {}", scriptId, invokeResult.getErrorCode().name(), invokeResult.getErrorDetails()); - throw e; - } - }, callbackExecutor); + return future; + } + + private JsInvokeProtos.RemoteJsRequest buildJsInvokeRequest(String scriptHash, String functionName, Object[] args, boolean includeScriptBody, String scriptBody) { + JsInvokeProtos.JsInvokeRequest.Builder jsRequestBuilder = JsInvokeProtos.JsInvokeRequest.newBuilder() + .setScriptHash(scriptHash) + .setFunctionName(functionName) + .setTimeout((int) maxExecRequestsTimeout); + if (includeScriptBody) jsRequestBuilder.setScriptBody(scriptBody); + for (Object arg : args) { + jsRequestBuilder.addArgs(arg.toString()); + } + + JsInvokeProtos.RemoteJsRequest jsRequestWrapper = JsInvokeProtos.RemoteJsRequest.newBuilder() + .setInvokeRequest(jsRequestBuilder.build()) + .build(); + return jsRequestWrapper; } @Override - protected void doRelease(UUID scriptId, String functionName) throws Exception { + protected void doRelease(UUID scriptId, String scriptHash, String functionName) throws Exception { + if (scriptIdToNameAndHashMap.values().stream().map(Pair::getSecond).anyMatch(hash -> hash.equals(scriptHash))) { + return; + } JsInvokeProtos.JsReleaseRequest jsRequest = JsInvokeProtos.JsReleaseRequest.newBuilder() - .setScriptIdMSB(scriptId.getMostSignificantBits()) - .setScriptIdLSB(scriptId.getLeastSignificantBits()) + .setScriptHash(scriptHash) .setFunctionName(functionName).build(); JsInvokeProtos.RemoteJsRequest jsRequestWrapper = JsInvokeProtos.RemoteJsRequest.newBuilder() @@ -244,12 +275,18 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { } JsInvokeProtos.RemoteJsResponse response = future.get().getValue(); - JsInvokeProtos.JsReleaseResponse compilationResult = response.getReleaseResponse(); - UUID compiledScriptId = new UUID(compilationResult.getScriptIdMSB(), compilationResult.getScriptIdLSB()); - if (compilationResult.getSuccess()) { - scriptIdToBodysMap.remove(scriptId); + JsInvokeProtos.JsReleaseResponse releaseResponse = response.getReleaseResponse(); + if (releaseResponse.getSuccess()) { + scriptsLock.lock(); + try { + if (scriptIdToNameAndHashMap.values().stream().map(Pair::getSecond).noneMatch(h -> h.equals(scriptHash))) { + scriptHashToBodysMap.remove(scriptHash); + } + } finally { + scriptsLock.unlock(); + } } else { - log.debug("[{}] Failed to release script due", compiledScriptId); + log.debug("[{}] Failed to release script", scriptHash); } } diff --git a/application/src/main/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngine.java b/application/src/main/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngine.java index c90e104ff4..f1374711d5 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngine.java +++ b/application/src/main/java/org/thingsboard/server/service/script/RuleNodeJsScriptEngine.java @@ -210,11 +210,11 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S return executeScriptAsync(msg.getCustomerId(), inArgs[0], inArgs[1], inArgs[2]); } - ListenableFuture executeScriptAsync(CustomerId customerId, Object... args) { + ListenableFuture executeScriptAsync(CustomerId customerId, String... args) { return Futures.transformAsync(sandboxService.invokeFunction(tenantId, customerId, this.scriptId, args), o -> { try { - return Futures.immediateFuture(mapper.readTree(o.toString())); + return Futures.immediateFuture(mapper.readTree(o)); } catch (Exception e) { if (e.getCause() instanceof ScriptException) { return Futures.immediateFailedFuture(e.getCause()); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 947754e405..a5f66968da 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.SettableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -115,6 +116,13 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer super.shutdownExecutor(); } + @Override + public ListenableFuture saveAndNotify(TenantId tenantId, EntityId entityId, TsKvEntry ts) { + SettableFuture future = SettableFuture.create(); + saveAndNotify(tenantId, entityId, Collections.singletonList(ts), new VoidFutureCallback(future)); + return future; + } + @Override public void saveAndNotify(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback) { saveAndNotify(tenantId, null, entityId, ts, 0L, callback); @@ -332,6 +340,34 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer , System.currentTimeMillis())), callback); } + @Override + public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value) { + SettableFuture future = SettableFuture.create(); + saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); + return future; + } + + @Override + public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, String value) { + SettableFuture future = SettableFuture.create(); + saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); + return future; + } + + @Override + public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, double value) { + SettableFuture future = SettableFuture.create(); + saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); + return future; + } + + @Override + public ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, boolean value) { + SettableFuture future = SettableFuture.create(); + saveAttrAndNotify(tenantId, entityId, scope, key, value, new VoidFutureCallback(future)); + return future; + } + private void onAttributesUpdate(TenantId tenantId, EntityId entityId, String scope, List attributes, boolean notifyDevice) { TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId); if (currentPartitions.contains(tpi)) { @@ -436,4 +472,22 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } } + private static class VoidFutureCallback implements FutureCallback { + private final SettableFuture future; + + public VoidFutureCallback(SettableFuture future) { + this.future = future; + } + + @Override + public void onSuccess(Void result) { + future.set(null); + } + + @Override + public void onFailure(Throwable t) { + future.setException(t); + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/AuditLogsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/AuditLogsCleanUpService.java new file mode 100644 index 0000000000..11b1751c0d --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/ttl/AuditLogsCleanUpService.java @@ -0,0 +1,61 @@ +/** + * Copyright © 2016-2022 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.server.service.ttl; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.thingsboard.server.dao.audit.AuditLogDao; +import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; +import org.thingsboard.server.queue.discovery.PartitionService; + +import java.util.concurrent.TimeUnit; + +import static org.thingsboard.server.dao.model.ModelConstants.AUDIT_LOG_COLUMN_FAMILY_NAME; + +@Service +@ConditionalOnExpression("${sql.ttl.audit_logs.enabled:true} && ${sql.ttl.audit_logs.ttl:0} > 0") +@Slf4j +public class AuditLogsCleanUpService extends AbstractCleanUpService { + + private final AuditLogDao auditLogDao; + private final SqlPartitioningRepository partitioningRepository; + + @Value("${sql.ttl.audit_logs.ttl:0}") + private long ttlInSec; + @Value("${sql.audit_logs.partition_size:168}") + private int partitionSizeInHours; + + public AuditLogsCleanUpService(PartitionService partitionService, AuditLogDao auditLogDao, SqlPartitioningRepository partitioningRepository) { + super(partitionService); + this.auditLogDao = auditLogDao; + this.partitioningRepository = partitioningRepository; + } + + @Scheduled(initialDelayString = "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.audit_logs.checking_interval_ms})}", + fixedDelayString = "${sql.ttl.audit_logs.checking_interval_ms}") + public void cleanUp() { + long auditLogsExpTime = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(ttlInSec); + if (isSystemTenantPartitionMine()) { + auditLogDao.cleanUpAuditLogs(auditLogsExpTime); + } else { + partitioningRepository.cleanupPartitionsCache(AUDIT_LOG_COLUMN_FAMILY_NAME, auditLogsExpTime, TimeUnit.HOURS.toMillis(partitionSizeInHours)); + } + } + +} diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 7b7dc2bba8..9f791cee9b 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -265,13 +265,17 @@ sql: batch_size: "${SQL_EDGE_EVENTS_BATCH_SIZE:1000}" batch_max_delay: "${SQL_EDGE_EVENTS_BATCH_MAX_DELAY_MS:100}" stats_print_interval_ms: "${SQL_EDGE_EVENTS_BATCH_STATS_PRINT_MS:10000}" + audit_logs: + partition_size: "${SQL_AUDIT_LOGS_PARTITION_SIZE_HOURS:168}" # Default value - 1 week # Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks - batch_sort: "${SQL_BATCH_SORT:false}" + batch_sort: "${SQL_BATCH_SORT:true}" # Specify whether to remove null characters from strValue of attributes and timeseries before insert remove_null_chars: "${SQL_REMOVE_NULL_CHARS:true}" # Specify whether to log database queries and their parameters generated by entity query repository log_queries: "${SQL_LOG_QUERIES:false}" log_queries_threshold: "${SQL_LOG_QUERIES_THRESHOLD:5000}" + log_tenant_stats: "${SQL_LOG_TENANT_STATS:true}" + log_tenant_stats_interval_ms: "${SQL_LOG_TENANT_STATS_INTERVAL_MS:60000}" postgres: # Specify partitioning size for timestamp key-value storage. Example: DAYS, MONTHS, YEARS, INDEFINITE. ts_key_value_partitioning: "${SQL_POSTGRES_TS_KV_PARTITIONING:MONTHS}" @@ -301,6 +305,10 @@ sql: rpc: enabled: "${SQL_TTL_RPC_ENABLED:true}" checking_interval: "${SQL_RPC_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours + audit_logs: + enabled: "${SQL_TTL_AUDIT_LOGS_ENABLED:true}" + ttl: "${SQL_TTL_AUDIT_LOGS_SECS:0}" # Disabled by default. Accuracy of the cleanup depends on the sql.audit_logs.partition_size + checking_interval_ms: "${SQL_TTL_AUDIT_LOGS_CHECKING_INTERVAL_MS:86400000}" # Default value - 1 day relations: max_level: "${SQL_RELATIONS_MAX_LEVEL:50}" # //This value has to be reasonable small to prevent infinite recursion as early as possible @@ -593,6 +601,9 @@ state: js: evaluator: "${JS_EVALUATOR:local}" # local/remote + max_total_args_size: "${JS_MAX_TOTAL_ARGS_SIZE:100000}" + max_result_size: "${JS_MAX_RESULT_SIZE:300000}" + max_script_body_size: "${JS_MAX_SCRIPT_BODY_SIZE:50000}" # Built-in JVM JavaScript environment properties local: # Use Sandboxed (secured) JVM JavaScript environment @@ -714,6 +725,8 @@ transport: dtls: # Enable/disable DTLS 1.2 support enabled: "${COAP_DTLS_ENABLED:false}" + # RFC7925_RETRANSMISSION_TIMEOUT_IN_MILLISECONDS = 9000 + retransmission_timeout: "${COAP_DTLS_RETRANSMISSION_TIMEOUT_MS:9000}" # CoAP DTLS bind address bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" # CoAP DTLS bind port @@ -751,6 +764,9 @@ transport: lwm2m: # Enable/disable lvm2m transport protocol. enabled: "${LWM2M_ENABLED:true}" + dtls: + # RFC7925_RETRANSMISSION_TIMEOUT_IN_MILLISECONDS = 9000 + retransmission_timeout: "${LWM2M_DTLS_RETRANSMISSION_TIMEOUT_MS:9000}" server: id: "${LWM2M_SERVER_ID:123}" bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index d204750e32..39421a4364 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -89,11 +89,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId); testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime, extractMatcherAdditionalInfo(additionalInfo)); - testPushMsgToRuleEngineNever(relation.getTo()); matcherOriginatorId = argument -> argument.equals(relation.getFrom()); testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime, extractMatcherAdditionalInfo(additionalInfo)); - testPushMsgToRuleEngineNever(relation.getFrom()); Mockito.reset(tbClusterService, auditLogService); } @@ -111,7 +109,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId); testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime * 2, 1); - testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, new Tenant(), cntTime); + testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, new Tenant(), cntTime * 3); Mockito.reset(tbClusterService, auditLogService); } @@ -141,11 +139,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { testNotificationMsgToEdgeServiceNeverWithActionType(entityId, actionType); testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId); - if (ActionType.RELATIONS_DELETED.equals(actionType)) { - testPushMsgToRuleEngineNever(originatorId); - } else { - testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime); - } + testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime); Mockito.reset(tbClusterService, auditLogService); } diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index ae3fc6d16d..3783b746f3 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -35,7 +35,7 @@ import org.junit.Rule; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; -import org.mockito.BDDMockito; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -132,8 +132,9 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { protected static final String DIFFERENT_CUSTOMER_USER_EMAIL = "testdifferentcustomer@thingsboard.org"; private static final String DIFFERENT_CUSTOMER_USER_PASSWORD = "diffcustomer"; - /** See {@link org.springframework.test.web.servlet.DefaultMvcResult#getAsyncResult(long)} - * and {@link org.springframework.mock.web.MockAsyncContext#getTimeout()} + /** + * See {@link org.springframework.test.web.servlet.DefaultMvcResult#getAsyncResult(long)} + * and {@link org.springframework.mock.web.MockAsyncContext#getTimeout()} */ private static final long DEFAULT_TIMEOUT = -1L; @@ -732,23 +733,18 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { protected void testEntityDaoWithRelationsTransactionalException(Dao dao, EntityId entityIdFrom, EntityId entityTo, String urlDelete) throws Exception { - entityDaoRemoveByIdWithException (dao); - createEntityRelation(entityIdFrom, entityTo, "TEST_TRANSACTIONAL_TYPE"); - assertThat(findRelationsByTo(entityTo)).hasSize(1); - - doDelete(urlDelete) - .andExpect(status().isInternalServerError()); - - assertThat(findRelationsByTo(entityTo)).hasSize(1); - } + Mockito.doThrow(new ConstraintViolationException("mock message", new SQLException(), "MOCK_CONSTRAINT")).when(dao).removeById(any(), any()); + try { + createEntityRelation(entityIdFrom, entityTo, "TEST_TRANSACTIONAL_TYPE"); + assertThat(findRelationsByTo(entityTo)).hasSize(1); - protected void entityDaoRemoveByIdWithException (Dao dao) throws Exception { - BDDMockito.willThrow(new ConstraintViolationException("mock message", new SQLException(), "MOCK_CONSTRAINT")) - .given(dao).removeById(any(), any()); - } + doDelete(urlDelete) + .andExpect(status().isInternalServerError()); - protected void afterTestEntityDaoRemoveByIdWithException (Dao dao) throws Exception { - BDDMockito.willCallRealMethod().given(dao).removeById(any(), any()); + assertThat(findRelationsByTo(entityTo)).hasSize(1); + } finally { + Mockito.reset(dao); + } } protected void createEntityRelation(EntityId entityIdFrom, EntityId entityIdTo, String typeRelation) throws Exception { @@ -761,9 +757,13 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { MvcResult mvcResult = doGet(url).andReturn(); switch (mvcResult.getResponse().getStatus()) { - case 200: return readResponse(mvcResult, new TypeReference<>() {}); - case 404: return Collections.emptyList(); + case 200: + return readResponse(mvcResult, new TypeReference<>() { + }); + case 404: + return Collections.emptyList(); } throw new AssertionError("Unexpected status " + mvcResult.getResponse().getStatus()); } + } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java index a2b8b908d5..4419e0e425 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java @@ -22,8 +22,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; @@ -43,16 +47,24 @@ import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @Slf4j +@ContextConfiguration(classes = {BaseAlarmControllerTest.Config.class}) public abstract class BaseAlarmControllerTest extends AbstractControllerTest { public static final String TEST_ALARM_TYPE = "Test"; protected Device customerDevice; - - @SpyBean + @Autowired private AlarmDao alarmDao; + static class Config { + @Bean + @Primary + public AlarmDao alarmDao(AlarmDao alarmDao) { + return Mockito.mock(AlarmDao.class, AdditionalAnswers.delegatesTo(alarmDao)); + } + } + @Before public void setup() throws Exception { loginTenantAdmin(); @@ -72,8 +84,6 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest { public void teardown() throws Exception { loginSysAdmin(); - afterTestEntityDaoRemoveByIdWithException (alarmDao); - deleteDifferentTenant(); } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java index 65b1687039..37cc703d55 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java @@ -21,8 +21,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityView; @@ -51,6 +55,7 @@ import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; +@ContextConfiguration(classes = {BaseAssetControllerTest.Config.class}) public abstract class BaseAssetControllerTest extends AbstractControllerTest { private IdComparator idComparator = new IdComparator<>(); @@ -58,9 +63,17 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { private Tenant savedTenant; private User tenantAdmin; - @SpyBean + @Autowired private AssetDao assetDao; + static class Config { + @Bean + @Primary + public AssetDao assetDao(AssetDao assetDao) { + return Mockito.mock(AssetDao.class, AdditionalAnswers.delegatesTo(assetDao)); + } + } + @Before public void beforeTest() throws Exception { loginSysAdmin(); @@ -84,8 +97,6 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { public void afterTest() throws Exception { loginSysAdmin(); - afterTestEntityDaoRemoveByIdWithException (assetDao); - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAssetProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAssetProfileControllerTest.java index 01b763a4b8..a911df798c 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAssetProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAssetProfileControllerTest.java @@ -20,8 +20,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.StringUtils; @@ -47,6 +51,7 @@ import java.util.stream.Collectors; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +@ContextConfiguration(classes = {BaseAssetProfileControllerTest.Config.class}) public abstract class BaseAssetProfileControllerTest extends AbstractControllerTest { private IdComparator idComparator = new IdComparator<>(); @@ -55,9 +60,17 @@ public abstract class BaseAssetProfileControllerTest extends AbstractControllerT private Tenant savedTenant; private User tenantAdmin; - @SpyBean + @Autowired private AssetProfileDao assetProfileDao; + static class Config { + @Bean + @Primary + public AssetProfileDao assetProfileDao(AssetProfileDao assetProfileDao) { + return Mockito.mock(AssetProfileDao.class, AdditionalAnswers.delegatesTo(assetProfileDao)); + } + } + @Before public void beforeTest() throws Exception { loginSysAdmin(); @@ -81,8 +94,6 @@ public abstract class BaseAssetProfileControllerTest extends AbstractControllerT public void afterTest() throws Exception { loginSysAdmin(); - afterTestEntityDaoRemoveByIdWithException (assetProfileDao); - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAuditLogControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAuditLogControllerTest.java index 5369d4d30a..c46f7d9c46 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAuditLogControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAuditLogControllerTest.java @@ -20,18 +20,33 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.mock.mockito.SpyBean; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.AuditLog; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.dao.audit.AuditLogDao; import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; +import org.thingsboard.server.service.ttl.AuditLogsCleanUpService; +import java.time.LocalDate; +import java.time.ZoneOffset; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; public abstract class BaseAuditLogControllerTest extends AbstractControllerTest { @@ -39,6 +54,18 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest private Tenant savedTenant; private User tenantAdmin; + @Autowired + private AuditLogDao auditLogDao; + @SpyBean + private SqlPartitioningRepository partitioningRepository; + @Autowired + private AuditLogsCleanUpService auditLogsCleanUpService; + + @Value("#{${sql.audit_logs.partition_size} * 60 * 60 * 1000}") + private long partitionDurationInMs; + @Value("${sql.ttl.audit_logs.ttl}") + private long auditLogsTtlInSec; + @Before public void beforeTest() throws Exception { loginSysAdmin(); @@ -145,4 +172,45 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest Assert.assertEquals(179, loadedAuditLogs.size()); } + + @Test + public void whenSavingNewAuditLog_thenCheckAndCreatePartitionIfNotExists() { + reset(partitioningRepository); + AuditLog auditLog = createAuditLog(ActionType.LOGIN, tenantAdminUserId); + verify(partitioningRepository).createPartitionIfNotExists(eq("audit_log"), eq(auditLog.getCreatedTime()), eq(partitionDurationInMs)); + + List partitions = partitioningRepository.fetchPartitions("audit_log"); + assertThat(partitions).singleElement().satisfies(partitionStartTs -> { + assertThat(partitionStartTs).isEqualTo(partitioningRepository.calculatePartitionStartTime(auditLog.getCreatedTime(), partitionDurationInMs)); + }); + } + + @Test + public void whenCleaningUpAuditLogsByTtl_thenDropOldPartitions() { + long oldAuditLogTs = LocalDate.of(2020, 10, 1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli(); + long partitionStartTs = partitioningRepository.calculatePartitionStartTime(oldAuditLogTs, partitionDurationInMs); + partitioningRepository.createPartitionIfNotExists("audit_log", oldAuditLogTs, partitionDurationInMs); + List partitions = partitioningRepository.fetchPartitions("audit_log"); + assertThat(partitions).contains(partitionStartTs); + + auditLogsCleanUpService.cleanUp(); + partitions = partitioningRepository.fetchPartitions("audit_log"); + assertThat(partitions).doesNotContain(partitionStartTs); + assertThat(partitions).allSatisfy(partitionsStart -> { + long partitionEndTs = partitionsStart + partitionDurationInMs; + assertThat(partitionEndTs).isGreaterThan(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(auditLogsTtlInSec)); + }); + } + + private AuditLog createAuditLog(ActionType actionType, EntityId entityId) { + AuditLog auditLog = new AuditLog(); + auditLog.setTenantId(tenantId); + auditLog.setCustomerId(null); + auditLog.setUserId(tenantAdminUserId); + auditLog.setEntityId(entityId); + auditLog.setUserName(tenantAdmin.getEmail()); + auditLog.setActionType(actionType); + return auditLogDao.save(tenantId, auditLog); + } + } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java index d3cc1761c7..029d3c98e6 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java @@ -24,8 +24,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.StringUtils; @@ -48,6 +52,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +@ContextConfiguration(classes = {BaseCustomerControllerTest.Config.class}) public abstract class BaseCustomerControllerTest extends AbstractControllerTest { static final TypeReference> PAGE_DATA_CUSTOMER_TYPE_REFERENCE = new TypeReference<>() { }; @@ -57,9 +62,18 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest private Tenant savedTenant; private User tenantAdmin; - @SpyBean + @Autowired private CustomerDao customerDao; + static class Config { + @Bean + @Primary + public CustomerDao customerDao(CustomerDao customerDao) { + return Mockito.mock(CustomerDao.class, AdditionalAnswers.delegatesTo(customerDao)); + } + } + + @Before public void beforeTest() throws Exception { executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass())); @@ -87,8 +101,6 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest loginSysAdmin(); - afterTestEntityDaoRemoveByIdWithException (customerDao); - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java index 50050c6306..c6bf570284 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java @@ -21,8 +21,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; @@ -46,6 +50,7 @@ import java.util.List; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +@ContextConfiguration(classes = {BaseDashboardControllerTest.Config.class}) public abstract class BaseDashboardControllerTest extends AbstractControllerTest { private IdComparator idComparator = new IdComparator<>(); @@ -53,9 +58,17 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest private Tenant savedTenant; private User tenantAdmin; - @SpyBean + @Autowired private DashboardDao dashboardDao; + static class Config { + @Bean + @Primary + public DashboardDao dashboardDao(DashboardDao dashboardDao) { + return Mockito.mock(DashboardDao.class, AdditionalAnswers.delegatesTo(dashboardDao)); + } + } + @Before public void beforeTest() throws Exception { loginSysAdmin(); @@ -79,8 +92,6 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest public void afterTest() throws Exception { loginSysAdmin(); - afterTestEntityDaoRemoveByIdWithException (dashboardDao); - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @@ -489,4 +500,5 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest dashboard.setTitle(title); return doPost("/api/dashboard", dashboard, Dashboard.class); } + } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java index abe8b78918..b97b346bd9 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java @@ -25,8 +25,13 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; @@ -69,8 +74,10 @@ import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; +@ContextConfiguration(classes = {BaseDeviceControllerTest.Config.class}) public abstract class BaseDeviceControllerTest extends AbstractControllerTest { - static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() {}; + static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() { + }; ListeningExecutorService executor; @@ -83,9 +90,16 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { @SpyBean private GatewayNotificationsService gatewayNotificationsService; - @SpyBean + @Autowired private DeviceDao deviceDao; + static class Config { + @Bean + @Primary + public DeviceDao deviceDao(DeviceDao deviceDao) { + return Mockito.mock(DeviceDao.class, AdditionalAnswers.delegatesTo(deviceDao)); + } + } @Before public void beforeTest() throws Exception { @@ -114,8 +128,6 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { loginSysAdmin(); - afterTestEntityDaoRemoveByIdWithException (deviceDao); - doDelete("/api/tenant/" + savedTenant.getId().getId()) .andExpect(status().isOk()); } @@ -464,9 +476,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { String customerIdStr = savedDevice.getId().toString(); doPost("/api/customer/" + customerIdStr - + "/device/" + savedDevice.getId().getId()) + + "/device/" + savedDevice.getId().getId()) .andExpect(status().isNotFound()) - .andExpect(statusReason(containsString(msgErrorNoFound("Customer", customerIdStr)))); + .andExpect(statusReason(containsString(msgErrorNoFound("Customer", customerIdStr)))); testNotifyEntityNever(savedDevice.getId(), savedDevice); testNotificationUpdateGatewayNever(); @@ -657,7 +669,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { doPost("/api/device/credentials", deviceCredentials) .andExpect(status().isNotFound()) - .andExpect(statusReason(containsString(msgErrorNoFound("Device", deviceTimeBasedId.toString())))); + .andExpect(statusReason(containsString(msgErrorNoFound("Device", deviceTimeBasedId.toString())))); testNotifyEntityNever(savedDevice.getId(), savedDevice); testNotificationUpdateGatewayNever(); @@ -1168,7 +1180,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { doPost("/api/edge/" + savedEdge.getId().getId() + "/device/" + savedDevice.getId().getId(), Device.class); - testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), + testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_EDGE, savedDevice.getId().getId().toString(), savedEdge.getId().getId().toString(), savedEdge.getName()); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java index 0c042d5006..b811497b9f 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java @@ -26,8 +26,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Device; @@ -69,6 +73,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; +@ContextConfiguration(classes = {BaseDeviceProfileControllerTest.Config.class}) public abstract class BaseDeviceProfileControllerTest extends AbstractControllerTest { private IdComparator idComparator = new IdComparator<>(); @@ -77,9 +82,17 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController private Tenant savedTenant; private User tenantAdmin; - @SpyBean + @Autowired private DeviceProfileDao deviceProfileDao; + static class Config { + @Bean + @Primary + public DeviceProfileDao deviceProfileDao(DeviceProfileDao deviceProfileDao) { + return Mockito.mock(DeviceProfileDao.class, AdditionalAnswers.delegatesTo(deviceProfileDao)); + } + } + @Before public void beforeTest() throws Exception { loginSysAdmin(); @@ -103,8 +116,6 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController public void afterTest() throws Exception { loginSysAdmin(); - afterTestEntityDaoRemoveByIdWithException (deviceProfileDao); - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @@ -1149,4 +1160,5 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController DeviceProfile deviceProfile = createDeviceProfile(name); return doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); } + } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java index 9582d6cbcf..4d852051fc 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java @@ -21,8 +21,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; @@ -65,6 +69,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @TestPropertySource(properties = { "edges.enabled=true", }) +@ContextConfiguration(classes = {BaseEdgeControllerTest.Config.class}) public abstract class BaseEdgeControllerTest extends AbstractControllerTest { public static final String EDGE_HOST = "localhost"; @@ -76,10 +81,18 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { private TenantId tenantId; private User tenantAdmin; - @SpyBean + @Autowired private EdgeDao edgeDao; - @Before + static class Config { + @Bean + @Primary + public EdgeDao edgeDao(EdgeDao edgeDao) { + return Mockito.mock(EdgeDao.class, AdditionalAnswers.delegatesTo(edgeDao)); + } + } + + @Before public void beforeTest() throws Exception { loginSysAdmin(); @@ -103,8 +116,6 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest { public void afterTest() throws Exception { loginSysAdmin(); - afterTestEntityDaoRemoveByIdWithException (edgeDao); - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 5bddb9b3a7..fe3fefc4e7 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -31,8 +31,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.web.servlet.ResultActions; import org.thingsboard.common.util.ThingsBoardExecutors; @@ -84,6 +88,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; "js.evaluator=mock", }) @Slf4j +@ContextConfiguration(classes = {BaseEntityViewControllerTest.Config.class}) public abstract class BaseEntityViewControllerTest extends AbstractControllerTest { static final TypeReference> PAGE_DATA_ENTITY_VIEW_TYPE_REF = new TypeReference<>() { }; @@ -96,9 +101,17 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes List> deleteFutures = new ArrayList<>(); ListeningExecutorService executor; - @SpyBean + @Autowired private EntityViewDao entityViewDao; + static class Config { + @Bean + @Primary + public EntityViewDao entityViewDao(EntityViewDao entityViewDao) { + return Mockito.mock(EntityViewDao.class, AdditionalAnswers.delegatesTo(entityViewDao)); + } + } + @Before public void beforeTest() throws Exception { executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass())); @@ -120,9 +133,6 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes @After public void afterTest() throws Exception { - - afterTestEntityDaoRemoveByIdWithException (entityViewDao); - executor.shutdownNow(); } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java index bec15dac8c..d32b1baa6b 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseRuleChainControllerTest.java @@ -20,8 +20,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; @@ -43,6 +47,7 @@ import java.util.List; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +@ContextConfiguration(classes = {BaseRuleChainControllerTest.Config.class}) public abstract class BaseRuleChainControllerTest extends AbstractControllerTest { private IdComparator idComparator = new IdComparator<>(); @@ -50,9 +55,17 @@ public abstract class BaseRuleChainControllerTest extends AbstractControllerTest private Tenant savedTenant; private User tenantAdmin; - @SpyBean + @Autowired private RuleChainDao ruleChainDao; + static class Config { + @Bean + @Primary + public RuleChainDao ruleChainDao(RuleChainDao ruleChainDao) { + return Mockito.mock(RuleChainDao.class, AdditionalAnswers.delegatesTo(ruleChainDao)); + } + } + @Before public void beforeTest() throws Exception { loginSysAdmin(); @@ -76,8 +89,6 @@ public abstract class BaseRuleChainControllerTest extends AbstractControllerTest public void afterTest() throws Exception { loginSysAdmin(); - afterTestEntityDaoRemoveByIdWithException(ruleChainDao); - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java index 141896ed4b..9c01f4323d 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java @@ -21,9 +21,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.After; import org.junit.Assert; import org.junit.Test; +import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; import org.springframework.http.HttpHeaders; +import org.springframework.test.context.ContextConfiguration; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; @@ -51,20 +55,27 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.dao.model.ModelConstants.SYSTEM_TENANT; +@ContextConfiguration(classes = {BaseUserControllerTest.Config.class}) public abstract class BaseUserControllerTest extends AbstractControllerTest { private IdComparator idComparator = new IdComparator<>(); private CustomerId customerNUULId = (CustomerId) createEntityId_NULL_UUID(new Customer()); - @SpyBean + @Autowired private UserDao userDao; + static class Config { + @Bean + @Primary + public UserDao userDao(UserDao userDao) { + return Mockito.mock(UserDao.class, AdditionalAnswers.delegatesTo(userDao)); + } + } + @After public void afterTest() throws Exception { loginSysAdmin(); - - afterTestEntityDaoRemoveByIdWithException(userDao); } @Test diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index e2a3b6e2d1..50c69110ad 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -26,6 +26,7 @@ import com.google.protobuf.AbstractMessage; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.MessageLite; +import io.netty.handler.codec.mqtt.MqttQoS; import org.awaitility.Awaitility; import org.junit.After; import org.junit.Assert; @@ -162,10 +163,11 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.transport.AbstractTransportIntegrationTest; import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; +import org.thingsboard.server.transport.mqtt.MqttTestCallback; +import org.thingsboard.server.transport.mqtt.MqttTestClient; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -174,11 +176,13 @@ import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertEquals; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; @TestPropertySource(properties = { "edges.enabled=true", + "transport.mqtt.enabled=true" }) abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -2147,6 +2151,42 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { Assert.assertEquals(queueUpdateMsg.getIdLSB(), savedQueue.getUuidId().getLeastSignificantBits()); } + @Test + public void sendUpdateSharedAttributeToCloudAndValidateDeviceSubscription() throws Exception { + Device device = saveDeviceOnCloudAndVerifyDeliveryToEdge(); + + DeviceCredentials deviceCredentials = doGet("/api/device/" + device.getUuidId() + "/credentials", DeviceCredentials.class); + + MqttTestClient client = new MqttTestClient(); + client.connectAndWait(deviceCredentials.getCredentialsId()); + MqttTestCallback onUpdateCallback = new MqttTestCallback(); + client.setCallback(onUpdateCallback); + client.subscribeAndWait("v1/devices/me/attributes", MqttQoS.AT_MOST_ONCE); + + edgeImitator.expectResponsesAmount(1); + + JsonObject attributesData = new JsonObject(); + String attrKey = "sharedAttrName"; + String attrValue = "sharedAttrValue"; + attributesData.addProperty(attrKey, attrValue); + UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder(); + EntityDataProto.Builder entityDataBuilder = EntityDataProto.newBuilder(); + entityDataBuilder.setEntityType(device.getId().getEntityType().name()); + entityDataBuilder.setEntityIdMSB(device.getId().getId().getMostSignificantBits()); + entityDataBuilder.setEntityIdLSB(device.getId().getId().getLeastSignificantBits()); + entityDataBuilder.setAttributesUpdatedMsg(JsonConverter.convertToAttributesProto(attributesData)); + entityDataBuilder.setPostAttributeScope(DataConstants.SHARED_SCOPE); + uplinkMsgBuilder.addEntityData(entityDataBuilder.build()); + + edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build()); + Assert.assertTrue(edgeImitator.waitForResponses()); + + Assert.assertTrue(onUpdateCallback.getSubscribeLatch().await(5, TimeUnit.SECONDS)); + + assertEquals(JacksonUtil.OBJECT_MAPPER.createObjectNode().put(attrKey, attrValue), + JacksonUtil.fromBytes(onUpdateCallback.getPayloadBytes())); + } + // Utility methods private Device saveDeviceOnCloudAndVerifyDeliveryToEdge() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/service/script/LocalJsInvokeServiceTest.java b/application/src/test/java/org/thingsboard/server/service/script/LocalJsInvokeServiceTest.java new file mode 100644 index 0000000000..039a69c01f --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/script/LocalJsInvokeServiceTest.java @@ -0,0 +1,96 @@ +/** + * Copyright © 2016-2022 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.server.service.script; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.test.context.TestPropertySource; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.controller.AbstractControllerTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@DaoSqlTest +@TestPropertySource(properties = { + "js.max_script_body_size=50", + "js.max_total_args_size=50", + "js.max_result_size=50", + "js.local.max_errors=2" +}) +class LocalJsInvokeServiceTest extends AbstractControllerTest { + + @Autowired + private NashornJsInvokeService jsInvokeService; + + @Value("${js.local.max_errors}") + private int maxJsErrors; + + @Test + void givenTooBigScriptForEval_thenReturnError() { + String hugeScript = "var a = 'qwertyqwertywertyqwabababer'; return {a: a};"; + + assertThatThrownBy(() -> { + evalScript(hugeScript); + }).hasMessageContaining("body exceeds maximum allowed size"); + } + + @Test + void givenTooBigScriptInputArgs_thenReturnErrorAndReportScriptExecutionError() throws Exception { + String script = "return { msg: msg };"; + String hugeMsg = "{\"input\":\"123456781234349\"}"; + UUID scriptId = evalScript(script); + + for (int i = 0; i < maxJsErrors; i++) { + assertThatThrownBy(() -> { + invokeScript(scriptId, hugeMsg); + }).hasMessageContaining("input arguments exceed maximum"); + } + assertThatScriptIsBlocked(scriptId); + } + + @Test + void whenScriptInvocationResultIsTooBig_thenReturnErrorAndReportScriptExecutionError() throws Exception { + String script = "var s = new Array(50).join('a'); return { s: s};"; + UUID scriptId = evalScript(script); + + for (int i = 0; i < maxJsErrors; i++) { + assertThatThrownBy(() -> { + invokeScript(scriptId, "{}"); + }).hasMessageContaining("result exceeds maximum allowed size"); + } + assertThatScriptIsBlocked(scriptId); + } + + private void assertThatScriptIsBlocked(UUID scriptId) { + assertThatThrownBy(() -> { + invokeScript(scriptId, "{}"); + }).hasMessageContaining("invocation is blocked due to maximum error"); + } + + private UUID evalScript(String script) throws ExecutionException, InterruptedException { + return jsInvokeService.eval(TenantId.SYS_TENANT_ID, JsScriptType.RULE_NODE_SCRIPT, script).get(); + } + + private String invokeScript(UUID scriptId, String msg) throws ExecutionException, InterruptedException { + return jsInvokeService.invokeFunction(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", "POST_TELEMETRY_REQUEST").get(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/service/script/MockJsInvokeService.java b/application/src/test/java/org/thingsboard/server/service/script/MockJsInvokeService.java index 17803bac96..1d91f50131 100644 --- a/application/src/test/java/org/thingsboard/server/service/script/MockJsInvokeService.java +++ b/application/src/test/java/org/thingsboard/server/service/script/MockJsInvokeService.java @@ -37,7 +37,7 @@ public class MockJsInvokeService implements JsInvokeService { } @Override - public ListenableFuture invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args) { + public ListenableFuture invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args) { log.warn("invokeFunction {} {} {} {}", tenantId, customerId, scriptId, args); return Futures.immediateFuture("{}"); } diff --git a/application/src/test/java/org/thingsboard/server/service/script/RemoteJsInvokeServiceTest.java b/application/src/test/java/org/thingsboard/server/service/script/RemoteJsInvokeServiceTest.java new file mode 100644 index 0000000000..30b9b0b2c0 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/script/RemoteJsInvokeServiceTest.java @@ -0,0 +1,219 @@ +/** + * Copyright © 2016-2022 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.server.service.script; + +import com.google.common.util.concurrent.Futures; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.server.common.data.ApiUsageState; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; +import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; +import org.thingsboard.server.queue.TbQueueRequestTemplate; +import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.usagestats.TbApiUsageClient; +import org.thingsboard.server.service.apiusage.TbApiUsageStateService; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +class RemoteJsInvokeServiceTest { + + private RemoteJsInvokeService remoteJsInvokeService; + private TbQueueRequestTemplate, TbProtoQueueMsg> jsRequestTemplate; + + + @BeforeEach + public void beforeEach() { + TbApiUsageStateService apiUsageStateService = mock(TbApiUsageStateService.class); + ApiUsageState apiUsageState = mock(ApiUsageState.class); + when(apiUsageState.isJsExecEnabled()).thenReturn(true); + when(apiUsageStateService.getApiUsageState(any())).thenReturn(apiUsageState); + TbApiUsageClient apiUsageClient = mock(TbApiUsageClient.class); + + remoteJsInvokeService = new RemoteJsInvokeService(apiUsageStateService, apiUsageClient); + jsRequestTemplate = mock(TbQueueRequestTemplate.class); + remoteJsInvokeService.requestTemplate = jsRequestTemplate; + } + + @AfterEach + public void afterEach() { + reset(jsRequestTemplate); + } + + @Test + public void whenInvokingFunction_thenDoNotSendScriptBody() throws Exception { + mockJsEvalResponse(); + String scriptBody = "return { a: 'b'};"; + UUID scriptId = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, JsScriptType.RULE_NODE_SCRIPT, scriptBody).get(); + reset(jsRequestTemplate); + + String expectedInvocationResult = "scriptInvocationResult"; + doReturn(Futures.immediateFuture(new TbProtoJsQueueMsg<>(UUID.randomUUID(), RemoteJsResponse.newBuilder() + .setInvokeResponse(JsInvokeProtos.JsInvokeResponse.newBuilder() + .setSuccess(true) + .setResult(expectedInvocationResult) + .build()) + .build()))) + .when(jsRequestTemplate).send(any()); + + ArgumentCaptor> jsRequestCaptor = ArgumentCaptor.forClass(TbProtoJsQueueMsg.class); + Object invocationResult = remoteJsInvokeService.invokeFunction(TenantId.SYS_TENANT_ID, null, scriptId, "{}").get(); + verify(jsRequestTemplate).send(jsRequestCaptor.capture()); + + JsInvokeProtos.JsInvokeRequest jsInvokeRequestMade = jsRequestCaptor.getValue().getValue().getInvokeRequest(); + assertThat(jsInvokeRequestMade.getScriptBody()).isNullOrEmpty(); + assertThat(jsInvokeRequestMade.getScriptHash()).isEqualTo(getScriptHash(scriptId)); + assertThat(invocationResult).isEqualTo(expectedInvocationResult); + } + + @Test + public void whenInvokingFunctionAndRemoteJsExecutorRemovedScript_thenHandleNotFoundErrorAndMakeInvokeRequestWithScriptBody() throws Exception { + mockJsEvalResponse(); + String scriptBody = "return { a: 'b'};"; + UUID scriptId = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, JsScriptType.RULE_NODE_SCRIPT, scriptBody).get(); + reset(jsRequestTemplate); + + doReturn(Futures.immediateFuture(new TbProtoJsQueueMsg<>(UUID.randomUUID(), RemoteJsResponse.newBuilder() + .setInvokeResponse(JsInvokeProtos.JsInvokeResponse.newBuilder() + .setSuccess(false) + .setErrorCode(JsInvokeProtos.JsInvokeErrorCode.NOT_FOUND_ERROR) + .build()) + .build()))) + .when(jsRequestTemplate).send(argThat(jsQueueMsg -> { + return StringUtils.isEmpty(jsQueueMsg.getValue().getInvokeRequest().getScriptBody()); + })); + + String expectedInvocationResult = "invocationResult"; + doReturn(Futures.immediateFuture(new TbProtoJsQueueMsg<>(UUID.randomUUID(), RemoteJsResponse.newBuilder() + .setInvokeResponse(JsInvokeProtos.JsInvokeResponse.newBuilder() + .setSuccess(true) + .setResult(expectedInvocationResult) + .build()) + .build()))) + .when(jsRequestTemplate).send(argThat(jsQueueMsg -> { + return StringUtils.isNotEmpty(jsQueueMsg.getValue().getInvokeRequest().getScriptBody()); + })); + + ArgumentCaptor> jsRequestsCaptor = ArgumentCaptor.forClass(TbProtoJsQueueMsg.class); + Object invocationResult = remoteJsInvokeService.invokeFunction(TenantId.SYS_TENANT_ID, null, scriptId, "{}").get(); + verify(jsRequestTemplate, times(2)).send(jsRequestsCaptor.capture()); + + List> jsInvokeRequestsMade = jsRequestsCaptor.getAllValues(); + + JsInvokeProtos.JsInvokeRequest firstRequestMade = jsInvokeRequestsMade.get(0).getValue().getInvokeRequest(); + assertThat(firstRequestMade.getScriptBody()).isNullOrEmpty(); + + JsInvokeProtos.JsInvokeRequest secondRequestMade = jsInvokeRequestsMade.get(1).getValue().getInvokeRequest(); + assertThat(secondRequestMade.getScriptBody()).contains(scriptBody); + + assertThat(jsInvokeRequestsMade.stream().map(TbProtoQueueMsg::getKey).distinct().count()).as("partition keys are same") + .isOne(); + + assertThat(invocationResult).isEqualTo(expectedInvocationResult); + } + + @Test + public void whenDoingEval_thenSaveScriptByHashOfTenantIdAndScriptBody() throws Exception { + mockJsEvalResponse(); + + TenantId tenantId1 = TenantId.fromUUID(UUID.randomUUID()); + String scriptBody1 = "var msg = { temp: 42, humidity: 77 };\n" + + "var metadata = { data: 40 };\n" + + "var msgType = \"POST_TELEMETRY_REQUEST\";\n" + + "\n" + + "return { msg: msg, metadata: metadata, msgType: msgType };"; + + Set scriptHashes = new HashSet<>(); + String tenant1Script1Hash = null; + for (int i = 0; i < 3; i++) { + UUID scriptUuid = remoteJsInvokeService.eval(tenantId1, JsScriptType.RULE_NODE_SCRIPT, scriptBody1).get(); + tenant1Script1Hash = getScriptHash(scriptUuid); + scriptHashes.add(tenant1Script1Hash); + } + assertThat(scriptHashes).as("Unique scripts ids").size().isOne(); + + TenantId tenantId2 = TenantId.fromUUID(UUID.randomUUID()); + UUID scriptUuid = remoteJsInvokeService.eval(tenantId2, JsScriptType.RULE_NODE_SCRIPT, scriptBody1).get(); + String tenant2Script1Id = getScriptHash(scriptUuid); + assertThat(tenant2Script1Id).isNotEqualTo(tenant1Script1Hash); + + String scriptBody2 = scriptBody1 + ";;"; + scriptUuid = remoteJsInvokeService.eval(tenantId2, JsScriptType.RULE_NODE_SCRIPT, scriptBody2).get(); + String tenant2Script2Id = getScriptHash(scriptUuid); + assertThat(tenant2Script2Id).isNotEqualTo(tenant2Script1Id); + } + + @Test + public void whenReleasingScript_thenCheckForHashUsages() throws Exception { + mockJsEvalResponse(); + String scriptBody = "return { a: 'b'};"; + UUID scriptId1 = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, JsScriptType.RULE_NODE_SCRIPT, scriptBody).get(); + UUID scriptId2 = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, JsScriptType.RULE_NODE_SCRIPT, scriptBody).get(); + String scriptHash = getScriptHash(scriptId1); + assertThat(scriptHash).isEqualTo(getScriptHash(scriptId2)); + reset(jsRequestTemplate); + + doReturn(Futures.immediateFuture(new TbProtoQueueMsg<>(UUID.randomUUID(), RemoteJsResponse.newBuilder() + .setReleaseResponse(JsInvokeProtos.JsReleaseResponse.newBuilder() + .setSuccess(true) + .build()) + .build()))) + .when(jsRequestTemplate).send(any()); + + remoteJsInvokeService.release(scriptId1).get(); + verifyNoInteractions(jsRequestTemplate); + assertThat(remoteJsInvokeService.scriptHashToBodysMap).containsKey(scriptHash); + + remoteJsInvokeService.release(scriptId2).get(); + verify(jsRequestTemplate).send(any()); + assertThat(remoteJsInvokeService.scriptHashToBodysMap).isEmpty(); + } + + private String getScriptHash(UUID scriptUuid) { + return remoteJsInvokeService.scriptIdToNameAndHashMap.get(scriptUuid).getSecond(); + } + + private void mockJsEvalResponse() { + doAnswer(methodCall -> Futures.immediateFuture(new TbProtoJsQueueMsg<>(UUID.randomUUID(), RemoteJsResponse.newBuilder() + .setCompileResponse(JsInvokeProtos.JsCompileResponse.newBuilder() + .setSuccess(true) + .setScriptHash(methodCall.>getArgument(0).getValue().getCompileRequest().getScriptHash()) + .build()) + .build()))) + .when(jsRequestTemplate).send(argThat(jsQueueMsg -> jsQueueMsg.getValue().hasCompileRequest())); + } + +} diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index 279d1e99be..eacd1733d3 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -56,4 +56,7 @@ queue.rule-engine.queues[2].processing-strategy.retries=1 queue.rule-engine.queues[2].processing-strategy.pause-between-retries=0 queue.rule-engine.queues[2].processing-strategy.max-pause-between-retries=0 -usage.stats.report.enabled=false \ No newline at end of file +usage.stats.report.enabled=false + +sql.audit_logs.partition_size=24 +sql.ttl.audit_logs.ttl=2592000 \ No newline at end of file diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java index d258aa3820..b8f814d613 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java @@ -29,6 +29,8 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; +import org.thingsboard.server.common.msg.edge.FromEdgeSyncResponse; +import org.thingsboard.server.common.msg.edge.ToEdgeSyncRequest; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; @@ -88,5 +90,9 @@ public interface TbClusterService extends TbQueueClusterService { void onEdgeEventUpdate(TenantId tenantId, EdgeId edgeId); + void pushEdgeSyncRequestToCore(ToEdgeSyncRequest toEdgeSyncRequest); + + void pushEdgeSyncResponseToCore(FromEdgeSyncResponse fromEdgeSyncResponse); + void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action); } diff --git a/common/cluster-api/src/main/proto/jsinvoke.proto b/common/cluster-api/src/main/proto/jsinvoke.proto index 8cae69f198..73f988af45 100644 --- a/common/cluster-api/src/main/proto/jsinvoke.proto +++ b/common/cluster-api/src/main/proto/jsinvoke.proto @@ -23,6 +23,7 @@ enum JsInvokeErrorCode { COMPILATION_ERROR = 0; RUNTIME_ERROR = 1; TIMEOUT_ERROR = 2; + NOT_FOUND_ERROR = 3; } message RemoteJsRequest { @@ -40,39 +41,34 @@ message RemoteJsResponse { } message JsCompileRequest { - int64 scriptIdMSB = 1; - int64 scriptIdLSB = 2; string functionName = 3; string scriptBody = 4; + string scriptHash = 5; } message JsReleaseRequest { - int64 scriptIdMSB = 1; - int64 scriptIdLSB = 2; string functionName = 3; + string scriptHash = 4; } message JsReleaseResponse { bool success = 1; - int64 scriptIdMSB = 2; - int64 scriptIdLSB = 3; + string scriptHash = 4; } message JsCompileResponse { bool success = 1; - int64 scriptIdMSB = 2; - int64 scriptIdLSB = 3; JsInvokeErrorCode errorCode = 4; string errorDetails = 5; + string scriptHash = 6; } message JsInvokeRequest { - int64 scriptIdMSB = 1; - int64 scriptIdLSB = 2; string functionName = 3; string scriptBody = 4; int32 timeout = 5; repeated string args = 6; + string scriptHash = 7; } message JsInvokeResponse { @@ -81,4 +77,3 @@ message JsInvokeResponse { JsInvokeErrorCode errorCode = 3; string errorDetails = 4; } - diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 1714e109a3..cb3443a71f 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -932,6 +932,8 @@ message ToCoreNotificationMsg { QueueUpdateMsg queueUpdateMsg = 5; QueueDeleteMsg queueDeleteMsg = 6; VersionControlResponseMsg vcResponseMsg = 7; + bytes toEdgeSyncRequestMsg = 8; + bytes fromEdgeSyncResponseMsg = 9; } /* Messages that are handled by ThingsBoard RuleEngine Service */ diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java index 7d5c17bf6d..cf8b47c82e 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java @@ -16,10 +16,8 @@ package org.thingsboard.server.coapserver; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.elements.config.CertificateAuthenticationMode; import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.elements.util.SslContextUtil; -import org.eclipse.californium.scandium.config.DtlsConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider; @@ -40,6 +38,13 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Collections; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.eclipse.californium.elements.config.CertificateAuthenticationMode.WANTED; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_CLIENT_AUTHENTICATION_MODE; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RETRANSMISSION_TIMEOUT; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_ROLE; +import static org.eclipse.californium.scandium.config.DtlsConfig.DtlsRole.SERVER_ONLY; + @Slf4j @ConditionalOnProperty(prefix = "transport.coap.dtls", value = "enabled", havingValue = "true", matchIfMissing = false) @Component @@ -51,6 +56,9 @@ public class TbCoapDtlsSettings { @Value("${transport.coap.dtls.bind_port}") private Integer port; + @Value("${transport.coap.dtls.retransmission_timeout:9000}") + private int dtlsRetransmissionTimeout; + @Bean @ConfigurationProperties(prefix = "transport.coap.dtls.credentials") public SslCredentialsConfig coapDtlsCredentials() { @@ -82,8 +90,9 @@ public class TbCoapDtlsSettings { SslCredentials sslCredentials = this.coapDtlsCredentialsConfig.getCredentials(); SslContextUtil.Credentials serverCredentials = new SslContextUtil.Credentials(sslCredentials.getPrivateKey(), null, sslCredentials.getCertificateChain()); - configBuilder.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY); - configBuilder.set(DtlsConfig.DTLS_CLIENT_AUTHENTICATION_MODE, CertificateAuthenticationMode.WANTED); + configBuilder.set(DTLS_CLIENT_AUTHENTICATION_MODE, WANTED); + configBuilder.set(DTLS_RETRANSMISSION_TIMEOUT, dtlsRetransmissionTimeout, MILLISECONDS); + configBuilder.set(DTLS_ROLE, SERVER_ONLY); configBuilder.setAdvancedCertificateVerifier( new TbCoapDtlsCertificateVerifier( transportService, diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java index 6497778676..5a5a78c2a2 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java @@ -39,6 +39,8 @@ public interface AttributesService { ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes); + ListenableFuture save(TenantId tenantId, EntityId entityId, String scope, AttributeKvEntry attribute); + ListenableFuture> removeAll(TenantId tenantId, EntityId entityId, String scope, List attributeKeys); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java index cf17eec88d..19d9cef81e 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.kv.TsKvEntry; import java.util.Collection; import java.util.List; +import java.util.Optional; /** * @author Andrew Shvayka @@ -37,6 +38,8 @@ public interface TimeseriesService { ListenableFuture> findAll(TenantId tenantId, EntityId entityId, List queries); + ListenableFuture> findLatest(TenantId tenantId, EntityId entityId, String keys); + ListenableFuture> findLatest(TenantId tenantId, EntityId entityId, Collection keys); ListenableFuture> findAllLatest(TenantId tenantId, EntityId entityId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/util/SqlDao.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/util/SqlDao.java new file mode 100644 index 0000000000..801d4af1a6 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/util/SqlDao.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2022 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.server.dao.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SqlDao { +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java index 90d95fb561..85b9e681a1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java @@ -79,6 +79,10 @@ public class DataConstants { public static final String ENTITY_ASSIGNED_TO_EDGE = "ENTITY_ASSIGNED_TO_EDGE"; public static final String ENTITY_UNASSIGNED_FROM_EDGE = "ENTITY_UNASSIGNED_FROM_EDGE"; + public static final String RELATION_ADD_OR_UPDATE = "RELATION_ADD_OR_UPDATE"; + public static final String RELATION_DELETED = "RELATION_DELETED"; + public static final String RELATIONS_DELETED = "RELATIONS_DELETED"; + public static final String RPC_CALL_FROM_SERVER_TO_DEVICE = "RPC_CALL_FROM_SERVER_TO_DEVICE"; public static final String RPC_QUEUED = "RPC_QUEUED"; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index da8edc695e..a66f3a40d9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -45,7 +45,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn @ToString(exclude = {"image", "profileDataBytes"}) @EqualsAndHashCode(callSuper = true) @Slf4j -public class DeviceProfile extends SearchTextBased implements HasName, HasTenantId, HasOtaPackage, ExportableEntity { +public class DeviceProfile extends SearchTextBased implements HasName, HasTenantId, HasOtaPackage, HasRuleEngineProfile, ExportableEntity { private static final long serialVersionUID = 6998485460273302018L; @@ -141,7 +141,7 @@ public class DeviceProfile extends SearchTextBased implements H } @ApiModelProperty(position = 5, value = "Used to mark the default profile. Default profile is used when the device profile is not specified during device creation.") - public boolean isDefault(){ + public boolean isDefault() { return isDefault; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HasRuleEngineProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/HasRuleEngineProfile.java new file mode 100644 index 0000000000..450a2235a7 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasRuleEngineProfile.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2022 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.server.common.data; + +import org.thingsboard.server.common.data.id.RuleChainId; + +public interface HasRuleEngineProfile { + + RuleChainId getDefaultRuleChainId(); + + String getDefaultQueueName(); + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java index 18d3dfff1e..9acbb15646 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java @@ -146,6 +146,16 @@ public class StringUtils { return org.apache.commons.lang3.StringUtils.substringAfterLast(str, sep); } + public static boolean containedByAny(String searchString, String... strings) { + if (searchString == null) return false; + for (String string : strings) { + if (string != null && string.contains(searchString)) { + return true; + } + } + return false; + } + public static String randomNumeric(int length) { return RandomStringUtils.randomNumeric(length); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java index 1bd9d9c6a5..01657feed6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java @@ -23,6 +23,7 @@ import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.HasName; +import org.thingsboard.server.common.data.HasRuleEngineProfile; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.AssetProfileId; @@ -37,7 +38,7 @@ import org.thingsboard.server.common.data.validation.NoXss; @ToString(exclude = {"image"}) @EqualsAndHashCode(callSuper = true) @Slf4j -public class AssetProfile extends SearchTextBased implements HasName, HasTenantId, ExportableEntity { +public class AssetProfile extends SearchTextBased implements HasName, HasTenantId, HasRuleEngineProfile, ExportableEntity { private static final long serialVersionUID = 6998485460273302018L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java b/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java index e87a1a6380..b921ea4374 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/audit/AuditLog.java @@ -22,6 +22,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.id.*; +import org.thingsboard.server.common.data.validation.NoXss; @ApiModel @EqualsAndHashCode(callSuper = true) @@ -34,6 +35,7 @@ public class AuditLog extends BaseData { private CustomerId customerId; @ApiModelProperty(position = 5, value = "JSON object with Entity id", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private EntityId entityId; + @NoXss @ApiModelProperty(position = 6, value = "Name of the logged entity", example = "Thermometer", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private String entityName; @ApiModelProperty(position = 7, value = "JSON object with User id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java b/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java index 269aa1e727..98c185b6b5 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java @@ -122,6 +122,12 @@ public enum MsgType { /** * Message that is sent on Edge Event to Edge Session */ - EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG; + EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG, + + /** + * Messages that are sent to and from edge session to start edge synchronization process + */ + EDGE_SYNC_REQUEST_TO_EDGE_SESSION_MSG, + EDGE_SYNC_RESPONSE_FROM_EDGE_SESSION_MSG; } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index 55b9f4dbd5..6d756af9dd 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -122,6 +122,16 @@ public final class TbMsg implements Serializable { data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback); } + public static TbMsg transformMsgData(TbMsg tbMsg, String data) { + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, + data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); + } + + public static TbMsg transformMsg(TbMsg tbMsg, TbMsgMetaData metadata) { + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata.copy(), tbMsg.dataType, + tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); + } + public static TbMsg transformMsg(TbMsg tbMsg, CustomerId customerId) { return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeEventUpdateMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeEventUpdateMsg.java index 3469cde65f..0285eef0b1 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeEventUpdateMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeEventUpdateMsg.java @@ -20,11 +20,9 @@ import lombok.ToString; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.MsgType; -import org.thingsboard.server.common.msg.aware.TenantAwareMsg; -import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; @ToString -public class EdgeEventUpdateMsg implements TenantAwareMsg, ToAllNodesMsg { +public class EdgeEventUpdateMsg implements EdgeSessionMsg { @Getter private final TenantId tenantId; @Getter diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeSessionMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeSessionMsg.java new file mode 100644 index 0000000000..c4719f9b29 --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/edge/EdgeSessionMsg.java @@ -0,0 +1,24 @@ +/** + * Copyright © 2016-2022 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.server.common.msg.edge; + +import org.thingsboard.server.common.msg.aware.TenantAwareMsg; +import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; + +import java.io.Serializable; + +public interface EdgeSessionMsg extends TenantAwareMsg, ToAllNodesMsg { +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/edge/FromEdgeSyncResponse.java b/common/message/src/main/java/org/thingsboard/server/common/msg/edge/FromEdgeSyncResponse.java new file mode 100644 index 0000000000..e93e5cd3b5 --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/edge/FromEdgeSyncResponse.java @@ -0,0 +1,39 @@ +/** + * Copyright © 2016-2022 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.server.common.msg.edge; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.msg.MsgType; + +import java.util.UUID; + +@AllArgsConstructor +@Getter +public class FromEdgeSyncResponse implements EdgeSessionMsg { + + private final UUID id; + private final TenantId tenantId; + private final EdgeId edgeId; + private final boolean success; + + @Override + public MsgType getMsgType() { + return MsgType.EDGE_SYNC_RESPONSE_FROM_EDGE_SESSION_MSG; + } +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/edge/ToEdgeSyncRequest.java b/common/message/src/main/java/org/thingsboard/server/common/msg/edge/ToEdgeSyncRequest.java new file mode 100644 index 0000000000..32e1068e73 --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/edge/ToEdgeSyncRequest.java @@ -0,0 +1,37 @@ +/** + * Copyright © 2016-2022 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.server.common.msg.edge; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.msg.MsgType; + +import java.util.UUID; + +@AllArgsConstructor +@Getter +public class ToEdgeSyncRequest implements EdgeSessionMsg { + private final UUID id; + private final TenantId tenantId; + private final EdgeId edgeId; + + @Override + public MsgType getMsgType() { + return MsgType.EDGE_SYNC_REQUEST_TO_EDGE_SESSION_MSG; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index b4572121a5..0afd4692e3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -37,8 +37,12 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.security.cert.X509Certificate; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RETRANSMISSION_TIMEOUT; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_ROLE; +import static org.eclipse.californium.scandium.config.DtlsConfig.DtlsRole.SERVER_ONLY; import static org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService.PSK_CIPHER_SUITES; import static org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES; import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig; @@ -88,10 +92,10 @@ public class LwM2MTransportBootstrapService { /* Create and Set DTLS Config */ DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig)); - dtlsConfig.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY); dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, serverConfig.isRecommendedSupportedGroups()); dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, serverConfig.isRecommendedCiphers()); - + dtlsConfig.set(DTLS_RETRANSMISSION_TIMEOUT, serverConfig.getDtlsRetransmissionTimeout(), MILLISECONDS); + dtlsConfig.set(DTLS_ROLE, SERVER_ONLY); setServerWithCredentials(builder, dtlsConfig); /* Set DTLS Config */ diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java index a9f75ff660..70d8c43cc6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java @@ -37,6 +37,10 @@ import java.util.List; @ConfigurationProperties(prefix = "transport.lwm2m") public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { + @Getter + @Value("${transport.lwm2m.dtls.retransmission_timeout:9000}") + private int dtlsRetransmissionTimeout; + @Getter @Value("${transport.lwm2m.timeout:}") private Long timeout; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index e4a9a2492f..7f8c333820 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -41,8 +41,12 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PreDestroy; import java.security.cert.X509Certificate; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RETRANSMISSION_TIMEOUT; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_ROLE; +import static org.eclipse.californium.scandium.config.DtlsConfig.DtlsRole.SERVER_ONLY; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; @@ -127,13 +131,13 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { builder.setSecurityStore(securityStore); builder.setRegistrationStore(registrationStore); - /* Create DTLS Config */ DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(config.getPort(), config.getSecurePort(), config)); - dtlsConfig.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY); dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, config.isRecommendedSupportedGroups()); dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, config.isRecommendedCiphers()); + dtlsConfig.set(DTLS_RETRANSMISSION_TIMEOUT, config.getDtlsRetransmissionTimeout(), MILLISECONDS); + dtlsConfig.set(DTLS_ROLE, SERVER_ONLY); /* Create credentials */ this.setServerWithCredentials(builder, dtlsConfig); diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index 9c4b68d3c0..98141e2a08 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -24,6 +24,8 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.thingsboard.server.common.data.kv.DataType; +import org.thingsboard.server.common.data.kv.KvEntry; import java.io.IOException; import java.util.ArrayList; @@ -212,4 +214,20 @@ public class JacksonUtil { } } } + + public static void addKvEntry(ObjectNode entityNode, KvEntry kvEntry) { + if (kvEntry.getDataType() == DataType.BOOLEAN) { + kvEntry.getBooleanValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); + } else if (kvEntry.getDataType() == DataType.DOUBLE) { + kvEntry.getDoubleValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); + } else if (kvEntry.getDataType() == DataType.LONG) { + kvEntry.getLongValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); + } else if (kvEntry.getDataType() == DataType.JSON) { + if (kvEntry.getJsonValue().isPresent()) { + entityNode.set(kvEntry.getKey(), JacksonUtil.toJsonNode(kvEntry.getJsonValue().get())); + } + } else { + entityNode.put(kvEntry.getKey(), kvEntry.getValueAsString()); + } + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index d842554ce0..35766e707a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -42,8 +42,6 @@ import java.util.UUID; */ public interface AlarmDao extends Dao { - Boolean deleteAlarm(TenantId tenantId, Alarm alarm); - ListenableFuture findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type); ListenableFuture findAlarmByIdAsync(TenantId tenantId, UUID key); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index f83a66fce9..7addad7051 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -153,7 +153,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } AlarmOperationResult result = new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm))); deleteEntityRelations(tenantId, alarm.getId()); - alarmDao.deleteAlarm(tenantId, alarm); + alarmDao.removeById(tenantId, alarm.getUuidId()); return result; } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); diff --git a/dao/src/main/java/org/thingsboard/server/dao/aspect/DbCallStats.java b/dao/src/main/java/org/thingsboard/server/dao/aspect/DbCallStats.java new file mode 100644 index 0000000000..06efa38cc5 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/aspect/DbCallStats.java @@ -0,0 +1,59 @@ +/** + * Copyright © 2016-2022 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.server.dao.aspect; + +import lombok.Data; +import org.springframework.data.util.Pair; +import org.thingsboard.server.common.data.id.TenantId; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; + +@Data +public class DbCallStats { + + private final TenantId tenantId; + private final ConcurrentMap methodStats = new ConcurrentHashMap<>(); + private final AtomicInteger successCalls = new AtomicInteger(); + private final AtomicInteger failureCalls = new AtomicInteger(); + + public void onMethodCall(String methodName, boolean success, long executionTime) { + var methodCallStats = methodStats.computeIfAbsent(methodName, m -> new MethodCallStats()); + methodCallStats.getExecutions().incrementAndGet(); + methodCallStats.getTiming().addAndGet(executionTime); + if (success) { + successCalls.incrementAndGet(); + } else { + failureCalls.incrementAndGet(); + methodCallStats.getFailures().incrementAndGet(); + } + } + + public DbCallStatsSnapshot snapshot() { + return DbCallStatsSnapshot.builder() + .tenantId(tenantId) + .totalSuccess(successCalls.get()) + .totalFailure(failureCalls.get()) + .methodStats(methodStats.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().snapshot()))) + .totalTiming(methodStats.values().stream().map(MethodCallStats::getTiming).map(AtomicLong::get).reduce(0L, Long::sum)) + .build(); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/aspect/DbCallStatsSnapshot.java b/dao/src/main/java/org/thingsboard/server/dao/aspect/DbCallStatsSnapshot.java new file mode 100644 index 0000000000..b29e3a1a7a --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/aspect/DbCallStatsSnapshot.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2022 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.server.dao.aspect; + +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.id.TenantId; + +import java.util.Map; + +@Data +@Builder +public class DbCallStatsSnapshot { + + private final TenantId tenantId; + private final int totalSuccess; + private final int totalFailure; + private final long totalTiming; + private final Map methodStats; + + public int getTotalCalls() { + return totalSuccess + totalFailure; + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/aspect/MethodCallStats.java b/dao/src/main/java/org/thingsboard/server/dao/aspect/MethodCallStats.java new file mode 100644 index 0000000000..22d9086964 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/aspect/MethodCallStats.java @@ -0,0 +1,33 @@ +/** + * Copyright © 2016-2022 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.server.dao.aspect; + +import lombok.Data; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +@Data +public class MethodCallStats { + private final AtomicInteger executions = new AtomicInteger(); + private final AtomicInteger failures = new AtomicInteger(); + private final AtomicLong timing = new AtomicLong(); + + public MethodCallStatsSnapshot snapshot() { + return new MethodCallStatsSnapshot(executions.get(), failures.get(), timing.get()); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/aspect/MethodCallStatsSnapshot.java b/dao/src/main/java/org/thingsboard/server/dao/aspect/MethodCallStatsSnapshot.java new file mode 100644 index 0000000000..75eff38c6d --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/aspect/MethodCallStatsSnapshot.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2022 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.server.dao.aspect; + +import lombok.Data; + +@Data +public class MethodCallStatsSnapshot { + private final int executions; + private final int failures; + private final long timing; +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/aspect/SqlDaoCallsAspect.java b/dao/src/main/java/org/thingsboard/server/dao/aspect/SqlDaoCallsAspect.java new file mode 100644 index 0000000000..9c4ca8c536 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/aspect/SqlDaoCallsAspect.java @@ -0,0 +1,241 @@ +/** + * Copyright © 2016-2022 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.server.dao.aspect; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.hibernate.exception.JDBCConnectionException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.id.TenantId; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import static org.apache.commons.lang3.StringUtils.join; + +@Aspect +@ConditionalOnProperty(prefix = "sql", value = "log_tenant_stats", havingValue = "true") +@Component +@Slf4j +public class SqlDaoCallsAspect { + + private final Set invalidTenantDbCallMethods = ConcurrentHashMap.newKeySet(); + private final ConcurrentMap statsMap = new ConcurrentHashMap<>(); + + @Value("${sql.batch_sort:true}") + private boolean batchSortEnabled; + + private static final String DEADLOCK_DETECTED_ERROR = "deadlock detected"; + + + @Scheduled(initialDelayString = "${sql.log_tenant_stats_interval_ms:60000}", + fixedDelayString = "${sql.log_tenant_stats_interval_ms:60000}") + public void printStats() { + List snapshots = snapshot(); + if (snapshots.isEmpty()) return; + try { + if (log.isTraceEnabled()) { + logTopNTenants(snapshots, Comparator.comparing(DbCallStatsSnapshot::getTotalTiming).reversed(), 0, snapshot -> { + logSnapshot(snapshot, 0, Comparator.comparing(MethodCallStatsSnapshot::getTiming).reversed(), log::trace); + }); + + Map> byMethodStats = new HashMap<>(); + for (DbCallStatsSnapshot snapshot : snapshots) { + snapshot.getMethodStats().forEach((method, stats) -> { + byMethodStats.computeIfAbsent(method, m -> new HashMap<>()) + .put(snapshot.getTenantId(), stats); + }); + } + byMethodStats.forEach((method, byTenantStats) -> { + log.trace("Top tenants for method {} by calls:", method); + byTenantStats.entrySet().stream() + .sorted(Map.Entry.comparingByValue(Comparator.comparing(MethodCallStatsSnapshot::getExecutions).reversed())) + .limit(10) + .forEach(e -> { + TenantId tenantId = e.getKey(); + MethodCallStatsSnapshot methodStats = e.getValue(); + log.trace("[{}] calls: {}, failures: {}, timing: {}", tenantId, + methodStats.getExecutions(), methodStats.getFailures(), methodStats.getTiming()); + }); + }); + } else if (log.isDebugEnabled()) { + log.debug("Total calls statistics below:"); + logTopNTenants(snapshots, Comparator.comparingInt(DbCallStatsSnapshot::getTotalCalls).reversed(), 10, + s -> logSnapshot(s, 10, Comparator.comparing(MethodCallStatsSnapshot::getExecutions).reversed(), log::debug)); + log.debug("Total timing statistics below:"); + logTopNTenants(snapshots, Comparator.comparingLong(DbCallStatsSnapshot::getTotalTiming).reversed(), + 10, s -> logSnapshot(s, 10, Comparator.comparing(MethodCallStatsSnapshot::getTiming).reversed(), log::debug)); + log.debug("Total errors statistics below:"); + logTopNTenants(snapshots, Comparator.comparingInt(DbCallStatsSnapshot::getTotalFailure).reversed(), + 10, s -> logSnapshot(s, 10, Comparator.comparing(MethodCallStatsSnapshot::getFailures).reversed(), log::debug)); + } else if (log.isInfoEnabled()) { + log.info("Total calls statistics below:"); + logTopNTenants(snapshots, Comparator.comparingInt(DbCallStatsSnapshot::getTotalFailure).reversed(), + 3, s -> logSnapshot(s, 3, Comparator.comparing(MethodCallStatsSnapshot::getFailures).reversed(), log::info)); + } + } finally { + statsMap.clear(); + } + } + + private void logSnapshot(DbCallStatsSnapshot snapshot, int limit, Comparator methodStatsComparator, Consumer logger) { + logger.accept(String.format("[%s]: calls: %s, failures: %s, exec time: %s ", + snapshot.getTenantId(), snapshot.getTotalCalls(), snapshot.getTotalFailure(), snapshot.getTotalTiming())); + var stream = snapshot.getMethodStats().entrySet().stream() + .sorted(Map.Entry.comparingByValue(methodStatsComparator)); + if (limit > 0) { + stream = stream.limit(limit); + } + stream.forEach(e -> { + MethodCallStatsSnapshot methodStats = e.getValue(); + logger.accept(String.format("[%s]: method: %s, calls: %s, failures: %s, exec time: %s", snapshot.getTenantId(), e.getKey(), + methodStats.getExecutions(), methodStats.getFailures(), methodStats.getTiming())); + }); + } + + private List snapshot() { + return statsMap.values().stream().map(DbCallStats::snapshot).collect(Collectors.toList()); + } + + private void logTopNTenants(List snapshots, Comparator comparator, + int n, Consumer logFunction) { + var stream = snapshots.stream().sorted(comparator); + if (n > 0) { + stream = stream.limit(n); + } + stream.forEach(logFunction); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Around("@within(org.thingsboard.server.dao.util.SqlDao)") + public Object handleSqlCall(ProceedingJoinPoint joinPoint) throws Throwable { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + var methodName = signature.toShortString(); + if (invalidTenantDbCallMethods.contains(methodName)) { + //Simply call the method if tenant is not found + return joinPoint.proceed(); + } + var tenantId = getTenantId(signature, methodName, joinPoint.getArgs()); + if (tenantId == null || tenantId.isNullUid()) { + //Simply call the method if tenant is null + return joinPoint.proceed(); + } + var startTime = System.currentTimeMillis(); + try { + var result = joinPoint.proceed(); + if (result instanceof ListenableFuture) { + Futures.addCallback((ListenableFuture) result, + new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Object result) { + reportSuccessfulMethodExecution(tenantId, methodName, startTime); + } + + @Override + public void onFailure(Throwable t) { + reportFailedMethodExecution(tenantId, methodName, startTime, t, joinPoint); + } + }, + MoreExecutors.directExecutor()); + } else { + reportSuccessfulMethodExecution(tenantId, methodName, startTime); + } + return result; + } catch (Throwable t) { + reportFailedMethodExecution(tenantId, methodName, startTime, t, joinPoint); + throw t; + } + } + + private void reportFailedMethodExecution(TenantId tenantId, String method, long startTime, Throwable t, ProceedingJoinPoint joinPoint) { + if (t != null) { + if (ExceptionUtils.indexOfThrowable(t, JDBCConnectionException.class) >= 0) { + return; + } + if (StringUtils.containedByAny(DEADLOCK_DETECTED_ERROR, ExceptionUtils.getRootCauseMessage(t), ExceptionUtils.getMessage(t))) { + if (!batchSortEnabled) { + log.warn("Deadlock was detected for method {} (tenant: {}). You might need to enable 'sql.batch_sort' option.", method, tenantId); + } else { + log.error("Deadlock was detected for method {} (tenant: {}). Arguments passed: \n{}\n The error: ", + method, tenantId, join(joinPoint.getArgs(), System.lineSeparator()), t); + } + } + } + reportMethodExecution(tenantId, method, false, startTime); + } + + private void reportSuccessfulMethodExecution(TenantId tenantId, String method, long startTime) { + reportMethodExecution(tenantId, method, true, startTime); + } + + private void reportMethodExecution(TenantId tenantId, String method, boolean success, long startTime) { + statsMap.computeIfAbsent(tenantId, DbCallStats::new) + .onMethodCall(method, success, System.currentTimeMillis() - startTime); + } + + TenantId getTenantId(MethodSignature signature, String methodName, Object[] args) { + if (args == null || args.length == 0) { + addAndLogInvalidMethods(methodName); + return null; + } + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + if (arg instanceof TenantId) { + return (TenantId) arg; + } else if (arg instanceof UUID) { + if (signature.getParameterNames() != null && StringUtils.equals(signature.getParameterNames()[i], "tenantId")) { + log.trace("Method {} uses UUID for tenantId param instead of TenantId class", methodName); + return TenantId.fromUUID((UUID) arg); + } + } + } + if (ArrayUtils.contains(signature.getParameterTypes(), TenantId.class) || + ArrayUtils.contains(signature.getParameterNames(), "tenantId")) { + log.debug("Null was submitted as tenantId to method {}. Args: {}", methodName, Arrays.toString(args)); + } else { + addAndLogInvalidMethods(methodName); + } + return null; + } + + private void addAndLogInvalidMethods(String methodName) { + invalidTenantDbCallMethods.add(methodName); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java index 97c263ad97..d9b7251f21 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java @@ -79,6 +79,13 @@ public class BaseAttributesService implements AttributesService { return attributesDao.findAllKeysByEntityIds(tenantId, entityType, entityIds); } + @Override + public ListenableFuture save(TenantId tenantId, EntityId entityId, String scope, AttributeKvEntry attribute) { + validate(entityId, scope); + AttributeUtils.validate(attribute); + return attributesDao.save(tenantId, entityId, scope, attribute); + } + @Override public ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes) { validate(entityId, scope); diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java index 802e746122..18c35741ff 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java @@ -205,6 +205,14 @@ public class CachedAttributesService implements AttributesService { return attributesDao.findAllKeysByEntityIds(tenantId, entityType, entityIds); } + @Override + public ListenableFuture save(TenantId tenantId, EntityId entityId, String scope, AttributeKvEntry attribute) { + validate(entityId, scope); + AttributeUtils.validate(attribute); + ListenableFuture future = attributesDao.save(tenantId, entityId, scope, attribute); + return Futures.transform(future, key -> evict(entityId, scope, attribute, key), cacheExecutor); + } + @Override public ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes) { validate(entityId, scope); @@ -213,17 +221,19 @@ public class CachedAttributesService implements AttributesService { List> futures = new ArrayList<>(attributes.size()); for (var attribute : attributes) { ListenableFuture future = attributesDao.save(tenantId, entityId, scope, attribute); - futures.add(Futures.transform(future, key -> { - log.trace("[{}][{}][{}] Before cache evict: {}", entityId, scope, key, attribute); - cache.evictOrPut(new AttributeCacheKey(scope, entityId, key), attribute); - log.trace("[{}][{}][{}] after cache evict.", entityId, scope, key); - return key; - }, cacheExecutor)); + futures.add(Futures.transform(future, key -> evict(entityId, scope, attribute, key), cacheExecutor)); } return Futures.allAsList(futures); } + private String evict(EntityId entityId, String scope, AttributeKvEntry attribute, String key) { + log.trace("[{}][{}][{}] Before cache evict: {}", entityId, scope, key, attribute); + cache.evictOrPut(new AttributeCacheKey(scope, entityId, key), attribute); + log.trace("[{}][{}][{}] after cache evict.", entityId, scope, key); + return key; + } + @Override public ListenableFuture> removeAll(TenantId tenantId, EntityId entityId, String scope, List attributeKeys) { validate(entityId, scope); diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogDao.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogDao.java index 939bc654b6..3f9b1ca01a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogDao.java @@ -39,4 +39,9 @@ public interface AuditLogDao extends Dao { PageData findAuditLogsByTenantIdAndUserId(UUID tenantId, UserId userId, List actionTypes, TimePageLink pageLink); PageData findAuditLogsByTenantId(UUID tenantId, List actionTypes, TimePageLink pageLink); + + void cleanUpAuditLogs(long expTime); + + void migrateAuditLogs(); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java index e3ea775b0e..da94141768 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java @@ -23,13 +23,13 @@ import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasName; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.audit.ActionStatus; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.AuditLog; @@ -382,7 +382,15 @@ public class AuditLogServiceImpl implements AuditLogService { AuditLog auditLogEntry = createAuditLogEntry(tenantId, entityId, entityName, customerId, userId, userName, actionType, actionData, actionStatus, actionFailureDetails); log.trace("Executing logAction [{}]", auditLogEntry); - auditLogValidator.validate(auditLogEntry, AuditLog::getTenantId); + try { + auditLogValidator.validate(auditLogEntry, AuditLog::getTenantId); + } catch (Exception e) { + if (StringUtils.contains(e.getMessage(), "value is malformed")) { + auditLogEntry.setEntityName("MALFORMED"); + } else { + return Futures.immediateFailedFuture(e); + } + } List> futures = Lists.newArrayListWithExpectedSize(INSERTS_PER_ENTRY); futures.add(auditLogDao.saveByTenantId(auditLogEntry)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java index 9bf729ad25..beb4a7ebc1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java @@ -35,7 +35,7 @@ import java.util.regex.Pattern; @Slf4j public abstract class DataValidator> { private static final Pattern EMAIL_PATTERN = - Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE); + Pattern.compile("^[A-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE); private static final Pattern QUEUE_PATTERN = Pattern.compile("^[a-zA-Z0-9_.\\-]+$"); @@ -62,7 +62,7 @@ public abstract class DataValidator> { } return old; } catch (DataValidationException e) { - log.error("Data object is invalid: [{}]", e.getMessage()); + log.error("{} object is invalid: [{}]", data == null ? "Data" : data.getClass().getSimpleName(), e.getMessage()); throw e; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java index ad6bb5ccec..81fc5d5ad9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.BaseEntity; +import org.thingsboard.server.dao.util.SqlDao; import java.util.Collection; import java.util.List; @@ -35,6 +36,7 @@ import java.util.UUID; * @author Valerii Sosliuk */ @Slf4j +@SqlDao public abstract class JpaAbstractDao, D> extends JpaAbstractDaoListeningExecutorService implements Dao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDaoListeningExecutorService.java b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDaoListeningExecutorService.java index d81e1a1323..b23be1a9cf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDaoListeningExecutorService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDaoListeningExecutorService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.sql; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; import java.sql.SQLException; @@ -32,6 +33,9 @@ public abstract class JpaAbstractDaoListeningExecutorService { @Autowired protected DataSource dataSource; + @Autowired + protected JdbcTemplate jdbcTemplate; + protected void printWarnings(Statement statement) throws SQLException { SQLWarning warnings = statement.getWarnings(); if (warnings != null) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index 8e165898a2..dc08d755b2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -42,6 +42,7 @@ import org.thingsboard.server.dao.model.sql.AlarmEntity; import org.thingsboard.server.dao.model.sql.EntityAlarmEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.sql.query.AlarmQueryRepository; +import org.thingsboard.server.dao.util.SqlDao; import java.util.Collection; import java.util.Collections; @@ -55,6 +56,7 @@ import java.util.UUID; */ @Slf4j @Component +@SqlDao public class JpaAlarmDao extends JpaAbstractDao implements AlarmDao { @Autowired @@ -76,11 +78,6 @@ public class JpaAlarmDao extends JpaAbstractDao implements A return alarmRepository; } - @Override - public Boolean deleteAlarm(TenantId tenantId, Alarm alarm) { - return removeById(tenantId, alarm.getUuidId()); - } - @Override public ListenableFuture findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type) { return service.submit(() -> { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java index 181ed7fc7b..489e15502e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java @@ -33,6 +33,7 @@ import org.thingsboard.server.dao.asset.AssetDao; import org.thingsboard.server.dao.model.sql.AssetEntity; import org.thingsboard.server.dao.model.sql.AssetInfoEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.ArrayList; import java.util.Collections; @@ -47,6 +48,7 @@ import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE * Created by Valerii Sosliuk on 5/19/2017. */ @Component +@SqlDao @Slf4j public class JpaAssetDao extends JpaAbstractSearchTextDao implements AssetDao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvInsertRepository.java index 472652e357..229d4f5740 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvInsertRepository.java @@ -25,6 +25,7 @@ import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import org.thingsboard.server.dao.model.sql.AttributeKvEntity; +import org.thingsboard.server.dao.util.SqlDao; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -35,6 +36,7 @@ import java.util.regex.Pattern; @Repository @Slf4j +@SqlDao public abstract class AttributeKvInsertRepository { private static final ThreadLocal PATTERN_THREAD_LOCAL = ThreadLocal.withInitial(() -> Pattern.compile(String.valueOf(Character.MIN_VALUE))); @@ -58,7 +60,7 @@ public abstract class AttributeKvInsertRepository { @Value("${sql.remove_null_chars:true}") private boolean removeNullChars; - protected void saveOrUpdate(List entities) { + public void saveOrUpdate(List entities) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java index 169ef55fbe..99ee1a9b00 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java @@ -37,6 +37,7 @@ import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService; import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent; import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams; import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper; +import org.thingsboard.server.dao.util.SqlDao; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -50,6 +51,7 @@ import java.util.stream.Collectors; @Component @Slf4j +@SqlDao public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService implements AttributesDao { @Autowired @@ -76,7 +78,7 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl @Value("${sql.attributes.batch_threads:4}") private int batchThreads; - @Value("${sql.batch_sort:false}") + @Value("${sql.batch_sort:true}") private boolean batchSortEnabled; private TbSqlBlockingQueueWrapper queue; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/SqlAttributesInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/SqlAttributesInsertRepository.java index e18f5178a8..adac4b4892 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/SqlAttributesInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/SqlAttributesInsertRepository.java @@ -17,9 +17,11 @@ package org.thingsboard.server.dao.sql.attributes; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; +import org.thingsboard.server.dao.util.SqlDao; @Repository @Transactional +@SqlDao public class SqlAttributesInsertRepository extends AttributeKvInsertRepository { } \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/audit/JpaAuditLogDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/audit/JpaAuditLogDao.java index 9c72bec397..1eefb21add 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/audit/JpaAuditLogDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/audit/JpaAuditLogDao.java @@ -15,31 +15,52 @@ */ package org.thingsboard.server.dao.sql.audit; +import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.common.util.concurrent.ListenableFuture; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.AuditLog; +import org.thingsboard.server.common.data.id.AuditLogId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.audit.AuditLogDao; +import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.sql.AuditLogEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; +import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; import java.util.List; import java.util.Objects; import java.util.UUID; +import java.util.concurrent.TimeUnit; @Component +@SqlDao +@RequiredArgsConstructor +@Slf4j public class JpaAuditLogDao extends JpaAbstractDao implements AuditLogDao { - @Autowired - private AuditLogRepository auditLogRepository; + private final AuditLogRepository auditLogRepository; + private final SqlPartitioningRepository partitioningRepository; + private final JdbcTemplate jdbcTemplate; + + @Value("${sql.audit_logs.partition_size:168}") + private int partitionSizeInHours; + @Value("${sql.ttl.audit_logs.ttl:0}") + private long ttlInSec; + + private static final String TABLE_NAME = ModelConstants.AUDIT_LOG_COLUMN_FAMILY_NAME; @Override protected Class getEntityClass() { @@ -59,6 +80,17 @@ public class JpaAuditLogDao extends JpaAbstractDao imp }); } + @Override + public AuditLog save(TenantId tenantId, AuditLog auditLog) { + if (auditLog.getId() == null) { + UUID uuid = Uuids.timeBased(); + auditLog.setId(new AuditLogId(uuid)); + auditLog.setCreatedTime(Uuids.unixTimestamp(uuid)); + } + partitioningRepository.createPartitionIfNotExists(TABLE_NAME, auditLog.getCreatedTime(), TimeUnit.HOURS.toMillis(partitionSizeInHours)); + return super.save(tenantId, auditLog); + } + @Override public PageData findAuditLogsByTenantIdAndEntityId(UUID tenantId, EntityId entityId, List actionTypes, TimePageLink pageLink) { return DaoUtil.toPageData( @@ -113,4 +145,41 @@ public class JpaAuditLogDao extends JpaAbstractDao imp actionTypes, DaoUtil.toPageable(pageLink))); } + + @Override + public void cleanUpAuditLogs(long expTime) { + partitioningRepository.dropPartitionsBefore(TABLE_NAME, expTime, TimeUnit.HOURS.toMillis(partitionSizeInHours)); + } + + @Override + public void migrateAuditLogs() { + long startTime = ttlInSec > 0 ? System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(ttlInSec) : 1480982400000L; + + long currentTime = System.currentTimeMillis(); + var partitionStepInMs = TimeUnit.HOURS.toMillis(partitionSizeInHours); + long numberOfPartitions = (currentTime - startTime) / partitionStepInMs; + + if (numberOfPartitions > 1000) { + String error = "Please adjust your audit logs partitioning configuration. Configuration with partition size " + + "of " + partitionSizeInHours + " hours and corresponding TTL will use " + numberOfPartitions + " " + + "(> 1000) partitions which is not recommended!"; + log.error(error); + throw new RuntimeException(error); + } + + while (startTime < currentTime) { + var endTime = startTime + partitionStepInMs; + log.info("Migrating audit logs for time period: {} - {}", startTime, endTime); + callMigrationFunction(startTime, endTime, partitionStepInMs); + startTime = endTime; + } + log.info("Audit logs migration finished"); + + jdbcTemplate.execute("DROP TABLE IF EXISTS old_audit_log"); + } + + private void callMigrationFunction(long startTime, long endTime, long partitionSizeInMs) { + jdbcTemplate.update("CALL migrate_audit_logs(?, ?, ?)", startTime, endTime, partitionSizeInMs); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java index ab3a4b4f8d..2db855db28 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java @@ -28,6 +28,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.model.sql.CustomerEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.Objects; import java.util.Optional; @@ -37,6 +38,7 @@ import java.util.UUID; * Created by Valerii Sosliuk on 5/6/2017. */ @Component +@SqlDao public class JpaCustomerDao extends JpaAbstractSearchTextDao implements CustomerDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java index 425c54c647..2e72155363 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java @@ -28,6 +28,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.dashboard.DashboardDao; import org.thingsboard.server.dao.model.sql.DashboardEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.List; import java.util.Optional; @@ -37,6 +38,7 @@ import java.util.UUID; * Created by Valerii Sosliuk on 5/6/2017. */ @Component +@SqlDao public class JpaDashboardDao extends JpaAbstractSearchTextDao implements DashboardDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java index d98312e7d5..98efbe917e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java @@ -27,6 +27,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.dashboard.DashboardInfoDao; import org.thingsboard.server.dao.model.sql.DashboardInfoEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.ArrayList; import java.util.List; @@ -38,6 +39,7 @@ import java.util.UUID; */ @Slf4j @Component +@SqlDao public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao implements DashboardInfoDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceCredentialsDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceCredentialsDao.java index e88b09a2bc..b1ffacc0e9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceCredentialsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceCredentialsDao.java @@ -25,6 +25,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.device.DeviceCredentialsDao; import org.thingsboard.server.dao.model.sql.DeviceCredentialsEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.UUID; @@ -32,6 +33,7 @@ import java.util.UUID; * Created by Valerii Sosliuk on 5/6/2017. */ @Component +@SqlDao public class JpaDeviceCredentialsDao extends JpaAbstractDao implements DeviceCredentialsDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java index 62516232d2..a00a1ba48f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java @@ -41,6 +41,7 @@ import org.thingsboard.server.dao.device.DeviceDao; import org.thingsboard.server.dao.model.sql.DeviceEntity; import org.thingsboard.server.dao.model.sql.DeviceInfoEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.ArrayList; import java.util.Collections; @@ -53,6 +54,7 @@ import java.util.UUID; * Created by Valerii Sosliuk on 5/6/2017. */ @Component +@SqlDao @Slf4j public class JpaDeviceDao extends JpaAbstractSearchTextDao implements DeviceDao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java index 6f4cd8587a..1a30c6627d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java @@ -32,12 +32,14 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.device.DeviceProfileDao; import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.Objects; import java.util.Optional; import java.util.UUID; @Component +@SqlDao public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao implements DeviceProfileDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java index 2f05f66cdf..df182659bf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java @@ -36,6 +36,7 @@ import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent; import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams; import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper; +import org.thingsboard.server.dao.util.SqlDao; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -53,6 +54,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @Slf4j @Component +@SqlDao public class JpaBaseEdgeEventDao extends JpaAbstractSearchTextDao implements EdgeEventDao { private final UUID systemTenantId = NULL_UUID; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java index 802c9b99b8..f7888e2ffd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java @@ -32,6 +32,7 @@ import org.thingsboard.server.dao.edge.EdgeDao; import org.thingsboard.server.dao.model.sql.EdgeEntity; import org.thingsboard.server.dao.model.sql.EdgeInfoEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.ArrayList; import java.util.Collections; @@ -42,6 +43,7 @@ import java.util.UUID; @Component @Slf4j +@SqlDao public class JpaEdgeDao extends JpaAbstractSearchTextDao implements EdgeDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java index 5cf70b021d..878195c4e2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java @@ -33,6 +33,7 @@ import org.thingsboard.server.dao.entityview.EntityViewDao; import org.thingsboard.server.dao.model.sql.EntityViewEntity; import org.thingsboard.server.dao.model.sql.EntityViewInfoEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.ArrayList; import java.util.Collections; @@ -46,6 +47,7 @@ import java.util.UUID; */ @Component @Slf4j +@SqlDao public class JpaEntityViewDao extends JpaAbstractSearchTextDao implements EntityViewDao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventInsertRepository.java index 85220ddf9f..cb91a5e674 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/EventInsertRepository.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.event.LifecycleEvent; import org.thingsboard.server.common.data.event.RuleChainDebugEvent; import org.thingsboard.server.common.data.event.RuleNodeDebugEvent; import org.thingsboard.server.common.data.event.StatisticsEvent; +import org.thingsboard.server.dao.util.SqlDao; import javax.annotation.PostConstruct; import java.sql.PreparedStatement; @@ -45,6 +46,7 @@ import java.util.stream.Collectors; @Repository @Transactional +@SqlDao public class EventInsertRepository { private static final ThreadLocal PATTERN_THREAD_LOCAL = ThreadLocal.withInitial(() -> Pattern.compile(String.valueOf(Character.MIN_VALUE))); @@ -81,7 +83,7 @@ public class EventInsertRepository { "VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING;"); } - protected void save(List entities) { + public void save(List entities) { Map> eventsByType = entities.stream().collect(Collectors.groupingBy(Event::getType, Collectors.toList())); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java index a9a3e25db2..4332319f0c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java @@ -18,10 +18,8 @@ package org.thingsboard.server.dao.sql.event; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; -import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.event.ErrorEventFilter; @@ -43,7 +41,7 @@ import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent; import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams; import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper; import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; -import org.thingsboard.server.dao.timeseries.SqlPartition; +import org.thingsboard.server.dao.util.SqlDao; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -53,7 +51,6 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; /** @@ -61,11 +58,9 @@ import java.util.function.Function; */ @Slf4j @Component +@SqlDao public class JpaBaseEventDao implements EventDao { - private final Map> partitionsByEventType = new ConcurrentHashMap<>(); - private static final ReentrantLock partitionCreationLock = new ReentrantLock(); - @Autowired private EventPartitionConfiguration partitionConfiguration; @@ -111,7 +106,7 @@ public class JpaBaseEventDao implements EventDao { @Value("${sql.events.batch_threads:3}") private int batchThreads; - @Value("${sql.batch_sort:false}") + @Value("${sql.batch_sort:true}") private boolean batchSortEnabled; private TbSqlBlockingQueueWrapper queue; @@ -120,9 +115,6 @@ public class JpaBaseEventDao implements EventDao { @PostConstruct private void init() { - for (EventType eventType : EventType.values()) { - partitionsByEventType.put(eventType, new ConcurrentHashMap<>()); - } TbSqlBlockingQueueParams params = TbSqlBlockingQueueParams.builder() .logName("Events") .batchSize(batchSize) @@ -163,42 +155,11 @@ public class JpaBaseEventDao implements EventDao { event.setCreatedTime(System.currentTimeMillis()); } } - savePartitionIfNotExist(event); + partitioningRepository.createPartitionIfNotExists(event.getType().getTable(), event.getCreatedTime(), + partitionConfiguration.getPartitionSizeInMs(event.getType())); return queue.add(event); } - private void savePartitionIfNotExist(Event event) { - EventType type = event.getType(); - var partitionsMap = partitionsByEventType.get(type); - var partitionDuration = partitionConfiguration.getPartitionSizeInMs(type); - long partitionStartTs = event.getCreatedTime() - (event.getCreatedTime() % partitionDuration); - if (partitionsMap.get(partitionStartTs) == null) { - savePartition(partitionsMap, new SqlPartition(type.getTable(), partitionStartTs, partitionStartTs + partitionDuration, Long.toString(partitionStartTs))); - } - } - - private void savePartition(Map partitionsMap, SqlPartition sqlPartition) { - if (!partitionsMap.containsKey(sqlPartition.getStart())) { - partitionCreationLock.lock(); - try { - log.trace("Saving partition: {}", sqlPartition); - partitioningRepository.save(sqlPartition); - log.trace("Adding partition to map: {}", sqlPartition); - partitionsMap.put(sqlPartition.getStart(), sqlPartition); - } catch (DataIntegrityViolationException ex) { - log.trace("Error occurred during partition save:", ex); - if (ex.getCause() instanceof ConstraintViolationException) { - log.warn("Saving partition [{}] rejected. Event data will save to the DEFAULT partition.", sqlPartition.getPartitionDate()); - partitionsMap.put(sqlPartition.getStart(), sqlPartition); - } else { - throw new RuntimeException(ex); - } - } finally { - partitionCreationLock.unlock(); - } - } - } - @Override public PageData findEvents(UUID tenantId, UUID entityId, EventType eventType, TimePageLink pageLink) { return DaoUtil.toPageData(getEventRepository(eventType).findEvents(tenantId, entityId, pageLink.getStartTime(), pageLink.getEndTime(), DaoUtil.toPageable(pageLink, EventEntity.eventColumnMap))); @@ -436,23 +397,24 @@ public class JpaBaseEventDao implements EventDao { log.info("Going to cleanup regular events with exp time: {}", regularEventExpTs); if (cleanupDb) { eventCleanupRepository.cleanupEvents(regularEventExpTs, false); + } else { + cleanupPartitionsCache(regularEventExpTs, false); } - cleanupPartitions(regularEventExpTs, false); } if (debugEventExpTs > 0) { log.info("Going to cleanup debug events with exp time: {}", debugEventExpTs); if (cleanupDb) { eventCleanupRepository.cleanupEvents(debugEventExpTs, true); + } else { + cleanupPartitionsCache(debugEventExpTs, true); } - cleanupPartitions(debugEventExpTs, true); } } - private void cleanupPartitions(long expTime, boolean isDebug) { + private void cleanupPartitionsCache(long expTime, boolean isDebug) { for (EventType eventType : EventType.values()) { if (eventType.isDebug() == isDebug) { - Map partitions = partitionsByEventType.get(eventType); - partitions.keySet().removeIf(startTs -> startTs + partitionConfiguration.getPartitionSizeInMs(eventType) < expTime); + partitioningRepository.cleanupPartitionsCache(eventType.getTable(), expTime, partitionConfiguration.getPartitionSizeInMs(eventType)); } } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/SqlEventCleanupRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/SqlEventCleanupRepository.java index 53786c448b..57073d34c5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/SqlEventCleanupRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/SqlEventCleanupRepository.java @@ -17,16 +17,12 @@ package org.thingsboard.server.dao.sql.event; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; import org.springframework.stereotype.Repository; import org.thingsboard.server.common.data.event.EventType; import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService; +import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.TimeUnit; @@ -34,13 +30,10 @@ import java.util.concurrent.TimeUnit; @Repository public class SqlEventCleanupRepository extends JpaAbstractDaoListeningExecutorService implements EventCleanupRepository { - private static final String SELECT_PARTITIONS_STMT = "SELECT tablename from pg_tables WHERE schemaname = 'public' and tablename like concat(?, '_%')"; - private static final int PSQL_VERSION_14 = 140000; - @Autowired private EventPartitionConfiguration partitionConfiguration; - - private volatile Integer currentServerVersion; + @Autowired + private SqlPartitioningRepository partitioningRepository; @Override public void cleanupEvents(long eventExpTime, boolean debug) { @@ -59,16 +52,13 @@ public class SqlEventCleanupRepository extends JpaAbstractDaoListeningExecutorSe callMigrateFunctionByPartitions("regular", "migrate_regular_events", regularEventTs, partitionConfiguration.getRegularPartitionSizeInHours()); callMigrateFunctionByPartitions("debug", "migrate_debug_events", debugEventTs, partitionConfiguration.getDebugPartitionSizeInHours()); - try (Connection connection = dataSource.getConnection(); - PreparedStatement dropFunction1 = connection.prepareStatement("DROP PROCEDURE IF EXISTS migrate_regular_events(bigint, bigint, int)"); - PreparedStatement dropFunction2 = connection.prepareStatement("DROP PROCEDURE IF EXISTS migrate_debug_events(bigint, bigint, int)"); - PreparedStatement dropTable = connection.prepareStatement("DROP TABLE IF EXISTS event")) { - dropFunction1.execute(); - dropFunction2.execute(); - dropTable.execute(); - } catch (SQLException e) { - log.error("SQLException occurred during drop of the `events` table", e); - throw new RuntimeException(e); + try { + jdbcTemplate.execute("DROP PROCEDURE IF EXISTS migrate_regular_events(bigint, bigint, int)"); + jdbcTemplate.execute("DROP PROCEDURE IF EXISTS migrate_debug_events(bigint, bigint, int)"); + jdbcTemplate.execute("DROP TABLE IF EXISTS event"); + } catch (DataAccessException e) { + log.error("Error occurred during drop of the `events` table", e); + throw e; } } @@ -94,13 +84,9 @@ public class SqlEventCleanupRepository extends JpaAbstractDaoListeningExecutorSe } private void callMigrateFunction(String functionName, long startTs, long endTs, int partitionSizeInHours) { - try (Connection connection = dataSource.getConnection(); - PreparedStatement stmt = connection.prepareStatement("call " + functionName + "(?,?,?)")) { - stmt.setLong(1, startTs); - stmt.setLong(2, endTs); - stmt.setInt(3, partitionSizeInHours); - stmt.execute(); - } catch (SQLException e) { + try { + jdbcTemplate.update("CALL " + functionName + "(?, ?, ?)", startTs, endTs, partitionSizeInHours); + } catch (DataAccessException e) { if (e.getMessage() == null || !e.getMessage().contains("relation \"event\" does not exist")) { log.error("[{}] SQLException occurred during execution of {} with parameters {} and {}", functionName, startTs, partitionSizeInHours, e); throw new RuntimeException(e); @@ -109,82 +95,7 @@ public class SqlEventCleanupRepository extends JpaAbstractDaoListeningExecutorSe } private void cleanupEvents(EventType eventType, long eventExpTime) { - var partitionDuration = partitionConfiguration.getPartitionSizeInMs(eventType); - List partitions = fetchPartitions(eventType); - for (var partitionTs : partitions) { - var partitionEndTs = partitionTs + partitionDuration; - if (partitionEndTs < eventExpTime) { - log.info("[{}] Detaching expired partition: [{}-{}]", eventType, partitionTs, partitionEndTs); - if (detachAndDropPartition(eventType, partitionTs)) { - log.info("[{}] Detached expired partition: {}", eventType, partitionTs); - } - } else { - log.debug("[{}] Skip valid partition: {}", eventType, partitionTs); - } - } - } - - private List fetchPartitions(EventType eventType) { - List partitions = new ArrayList<>(); - try (Connection connection = dataSource.getConnection(); - PreparedStatement stmt = connection.prepareStatement(SELECT_PARTITIONS_STMT)) { - stmt.setString(1, eventType.getTable()); - stmt.execute(); - try (ResultSet resultSet = stmt.getResultSet()) { - while (resultSet.next()) { - String partitionTableName = resultSet.getString(1); - String partitionTsStr = partitionTableName.substring(eventType.getTable().length() + 1); - try { - partitions.add(Long.parseLong(partitionTsStr)); - } catch (NumberFormatException nfe) { - log.warn("Failed to parse table name: {}", partitionTableName); - } - } - } - } catch (SQLException e) { - log.error("SQLException occurred during events TTL task execution ", e); - } - return partitions; - } - - private boolean detachAndDropPartition(EventType eventType, long partitionTs) { - String tablePartition = eventType.getTable() + "_" + partitionTs; - String detachPsqlStmtStr = "ALTER TABLE " + eventType.getTable() + " DETACH PARTITION " + tablePartition; - if (getCurrentServerVersion() >= PSQL_VERSION_14) { - detachPsqlStmtStr += " CONCURRENTLY"; - } - - String dropStmtStr = "DROP TABLE " + tablePartition; - try (Connection connection = dataSource.getConnection(); - PreparedStatement detachStmt = connection.prepareStatement(detachPsqlStmtStr); - PreparedStatement dropStmt = connection.prepareStatement(dropStmtStr)) { - detachStmt.execute(); - dropStmt.execute(); - return true; - } catch (SQLException e) { - log.error("[{}] SQLException occurred during detach and drop of the partition: {}", eventType, partitionTs, e); - } - return false; - } - - private synchronized int getCurrentServerVersion() { - if (currentServerVersion == null) { - try (Connection connection = dataSource.getConnection(); - PreparedStatement versionStmt = connection.prepareStatement("SELECT current_setting('server_version_num')")) { - versionStmt.execute(); - try (ResultSet resultSet = versionStmt.getResultSet()) { - while (resultSet.next()) { - currentServerVersion = resultSet.getInt(1); - } - } - } catch (SQLException e) { - log.warn("SQLException occurred during fetch of the server version", e); - } - if (currentServerVersion == null) { - currentServerVersion = 0; - } - } - return currentServerVersion; + partitioningRepository.dropPartitionsBefore(eventType.getTable(), eventExpTime, partitionConfiguration.getPartitionSizeInMs(eventType)); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationTemplateDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationTemplateDao.java index 344f8e97db..61b98886ba 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationTemplateDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationTemplateDao.java @@ -23,6 +23,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.OAuth2ClientRegistrationTemplateEntity; import org.thingsboard.server.dao.oauth2.OAuth2ClientRegistrationTemplateDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.ArrayList; import java.util.List; @@ -31,6 +32,7 @@ import java.util.UUID; @Component @RequiredArgsConstructor +@SqlDao public class JpaOAuth2ClientRegistrationTemplateDao extends JpaAbstractDao implements OAuth2ClientRegistrationTemplateDao { private final OAuth2ClientRegistrationTemplateRepository repository; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2DomainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2DomainDao.java index e191fc12f4..c1be2d86bc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2DomainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2DomainDao.java @@ -23,12 +23,14 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.OAuth2DomainEntity; import org.thingsboard.server.dao.oauth2.OAuth2DomainDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.List; import java.util.UUID; @Component @RequiredArgsConstructor +@SqlDao public class JpaOAuth2DomainDao extends JpaAbstractDao implements OAuth2DomainDao { private final OAuth2DomainRepository repository; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2MobileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2MobileDao.java index 94fc0a9a17..2b4cc39001 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2MobileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2MobileDao.java @@ -23,12 +23,14 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.OAuth2MobileEntity; import org.thingsboard.server.dao.oauth2.OAuth2MobileDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.List; import java.util.UUID; @Component @RequiredArgsConstructor +@SqlDao public class JpaOAuth2MobileDao extends JpaAbstractDao implements OAuth2MobileDao { private final OAuth2MobileRepository repository; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ParamsDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ParamsDao.java index d18494a015..51e1dcbfe9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ParamsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ParamsDao.java @@ -22,11 +22,13 @@ import org.thingsboard.server.common.data.oauth2.OAuth2Params; import org.thingsboard.server.dao.model.sql.OAuth2ParamsEntity; import org.thingsboard.server.dao.oauth2.OAuth2ParamsDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.UUID; @Component @RequiredArgsConstructor +@SqlDao public class JpaOAuth2ParamsDao extends JpaAbstractDao implements OAuth2ParamsDao { private final OAuth2ParamsRepository repository; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2RegistrationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2RegistrationDao.java index 0a0021bf66..8703b6880a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2RegistrationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2RegistrationDao.java @@ -25,12 +25,14 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.OAuth2RegistrationEntity; import org.thingsboard.server.dao.oauth2.OAuth2RegistrationDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.List; import java.util.UUID; @Component @RequiredArgsConstructor +@SqlDao public class JpaOAuth2RegistrationDao extends JpaAbstractDao implements OAuth2RegistrationDao { private final OAuth2RegistrationRepository repository; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java index 6af11346fd..26d425a964 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java @@ -25,11 +25,13 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.sql.OtaPackageEntity; import org.thingsboard.server.dao.ota.OtaPackageDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.UUID; @Slf4j @Component +@SqlDao public class JpaOtaPackageDao extends JpaAbstractSearchTextDao implements OtaPackageDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageInfoDao.java index ab8528c3ff..07e341b320 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageInfoDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageInfoDao.java @@ -30,12 +30,14 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.OtaPackageInfoEntity; import org.thingsboard.server.dao.ota.OtaPackageInfoDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.Objects; import java.util.UUID; @Slf4j @Component +@SqlDao public class JpaOtaPackageInfoDao extends JpaAbstractSearchTextDao implements OtaPackageInfoDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/queue/JpaQueueDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/queue/JpaQueueDao.java index 3d68a08f0a..f11952f3e9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/queue/JpaQueueDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/queue/JpaQueueDao.java @@ -28,6 +28,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.QueueEntity; import org.thingsboard.server.dao.queue.QueueDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.List; import java.util.Objects; @@ -35,6 +36,7 @@ import java.util.UUID; @Slf4j @Component +@SqlDao public class JpaQueueDao extends JpaAbstractDao implements QueueDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 422e0a8623..e4b51d62f1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -32,6 +32,7 @@ import org.thingsboard.server.dao.model.sql.RelationCompositeKey; import org.thingsboard.server.dao.model.sql.RelationEntity; import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService; +import org.thingsboard.server.dao.util.SqlDao; import java.util.ArrayList; import java.util.Arrays; @@ -44,6 +45,7 @@ import java.util.stream.Collectors; */ @Slf4j @Component +@SqlDao public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService implements RelationDao { private static final List ALL_TYPE_GROUP_NAMES = new ArrayList<>(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java index 5e4914f470..e3fdb90aee 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java @@ -28,6 +28,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.TbResourceEntity; import org.thingsboard.server.dao.resource.TbResourceDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.List; import java.util.Objects; @@ -35,6 +36,7 @@ import java.util.UUID; @Slf4j @Component +@SqlDao public class JpaTbResourceDao extends JpaAbstractSearchTextDao implements TbResourceDao { private final TbResourceRepository resourceRepository; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java index e2d68a6db4..0a80efad14 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java @@ -27,12 +27,14 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.TbResourceInfoEntity; import org.thingsboard.server.dao.resource.TbResourceInfoDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.Objects; import java.util.UUID; @Slf4j @Component +@SqlDao public class JpaTbResourceInfoDao extends JpaAbstractSearchTextDao implements TbResourceInfoDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/JpaRpcDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/JpaRpcDao.java index 6c30b85d31..1ccd5270f3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/JpaRpcDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rpc/JpaRpcDao.java @@ -30,12 +30,14 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RpcEntity; import org.thingsboard.server.dao.rpc.RpcDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.UUID; @Slf4j @Component @AllArgsConstructor +@SqlDao public class JpaRpcDao extends JpaAbstractDao implements RpcDao { private final RpcRepository rpcRepository; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index 9ec2bab280..b9b991bc15 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java @@ -30,6 +30,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RuleChainEntity; import org.thingsboard.server.dao.rule.RuleChainDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.Collection; import java.util.Objects; @@ -38,6 +39,7 @@ import java.util.UUID; @Slf4j @Component +@SqlDao public class JpaRuleChainDao extends JpaAbstractSearchTextDao implements RuleChainDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java index 7fc1229cd3..9a768871af 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java @@ -30,6 +30,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RuleNodeEntity; import org.thingsboard.server.dao.rule.RuleNodeDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.List; import java.util.Objects; @@ -38,6 +39,7 @@ import java.util.stream.Collectors; @Slf4j @Component +@SqlDao public class JpaRuleNodeDao extends JpaAbstractSearchTextDao implements RuleNodeDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeStateDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeStateDao.java index 9b8c7ff8e7..760cb0fdc5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeStateDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeStateDao.java @@ -27,11 +27,13 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.RuleNodeStateEntity; import org.thingsboard.server.dao.rule.RuleNodeStateDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.UUID; @Slf4j @Component +@SqlDao public class JpaRuleNodeStateDao extends JpaAbstractDao implements RuleNodeStateDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/settings/JpaAdminSettingsDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/settings/JpaAdminSettingsDao.java index bd815bc410..f335dac81b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/settings/JpaAdminSettingsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/settings/JpaAdminSettingsDao.java @@ -26,10 +26,12 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.AdminSettingsEntity; import org.thingsboard.server.dao.settings.AdminSettingsDao; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.UUID; @Component +@SqlDao @Slf4j public class JpaAdminSettingsDao extends JpaAbstractDao implements AdminSettingsDao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java index dfbae0e9b7..635b138815 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java @@ -30,6 +30,7 @@ import org.thingsboard.server.dao.model.sql.TenantEntity; import org.thingsboard.server.dao.model.sql.TenantInfoEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.List; import java.util.Objects; @@ -41,6 +42,7 @@ import java.util.stream.Collectors; * Created by Valerii Sosliuk on 4/30/2017. */ @Component +@SqlDao public class JpaTenantDao extends JpaAbstractSearchTextDao implements TenantDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantProfileDao.java index 3cad31f553..cc35af7519 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantProfileDao.java @@ -27,11 +27,13 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.TenantProfileEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.tenant.TenantProfileDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.Objects; import java.util.UUID; @Component +@SqlDao public class JpaTenantProfileDao extends JpaAbstractSearchTextDao implements TenantProfileDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/JpaApiUsageStateDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/JpaApiUsageStateDao.java index 96a0ecaede..d950a3c9fa 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/JpaApiUsageStateDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/JpaApiUsageStateDao.java @@ -25,6 +25,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.ApiUsageStateEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.usagerecord.ApiUsageStateDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.UUID; @@ -32,6 +33,7 @@ import java.util.UUID; * @author Andrii Shvaika */ @Component +@SqlDao public class JpaApiUsageStateDao extends JpaAbstractDao implements ApiUsageStateDao { private final ApiUsageStateRepository apiUsageStateRepository; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserAuthSettingsDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserAuthSettingsDao.java index 55cc195f6b..3759ab88b5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserAuthSettingsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserAuthSettingsDao.java @@ -24,11 +24,13 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.UserAuthSettingsEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.user.UserAuthSettingsDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.UUID; @Component @RequiredArgsConstructor +@SqlDao public class JpaUserAuthSettingsDao extends JpaAbstractDao implements UserAuthSettingsDao { private final UserAuthSettingsRepository repository; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserCredentialsDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserCredentialsDao.java index 69f83efc86..2a9381b3df 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserCredentialsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserCredentialsDao.java @@ -24,6 +24,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.UserCredentialsEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.user.UserCredentialsDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.UUID; @@ -31,6 +32,7 @@ import java.util.UUID; * Created by Valerii Sosliuk on 4/22/2017. */ @Component +@SqlDao public class JpaUserCredentialsDao extends JpaAbstractDao implements UserCredentialsDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java index dc632091c7..ad8cac6a28 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java @@ -28,6 +28,7 @@ import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.UserEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.user.UserDao; +import org.thingsboard.server.dao.util.SqlDao; import java.util.Objects; import java.util.UUID; @@ -38,6 +39,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; * @author Valerii Sosliuk */ @Component +@SqlDao public class JpaUserDao extends JpaAbstractSearchTextDao implements UserDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java index eac0a15b1e..96e22142f8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.WidgetTypeDetailsEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.util.SqlDao; import org.thingsboard.server.dao.widget.WidgetTypeDao; import java.util.List; @@ -35,6 +36,7 @@ import java.util.UUID; * Created by Valerii Sosliuk on 4/29/2017. */ @Component +@SqlDao public class JpaWidgetTypeDao extends JpaAbstractDao implements WidgetTypeDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java index 1ae399e28d..cf201efa36 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.sql.WidgetsBundleEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; +import org.thingsboard.server.dao.util.SqlDao; import org.thingsboard.server.dao.widget.WidgetsBundleDao; import java.util.Objects; @@ -40,6 +41,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; * Created by Valerii Sosliuk on 4/23/2017. */ @Component +@SqlDao public class JpaWidgetsBundleDao extends JpaAbstractSearchTextDao implements WidgetsBundleDao { @Autowired diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java index 3de21e41bf..8439a4a063 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java @@ -63,7 +63,7 @@ public abstract class AbstractSqlTimeseriesDao extends BaseAbstractSqlTimeseries @Value("${sql.timescale.batch_threads:4}") protected int timescaleBatchThreads; - @Value("${sql.batch_sort:false}") + @Value("${sql.batch_sort:true}") protected boolean batchSortEnabled; @Value("${sql.ttl.ts.ts_key_value_ttl:0}") diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java index 50975f21de..214f7f0d92 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java @@ -94,7 +94,7 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme @Value("${sql.ts_latest.batch_threads:4}") private int tsLatestBatchThreads; - @Value("${sql.batch_sort:false}") + @Value("${sql.batch_sort:true}") protected boolean batchSortEnabled; @Autowired @@ -149,9 +149,18 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme return getRemoveLatestFuture(tenantId, entityId, query); } + @Override + public ListenableFuture> findLatestOpt(TenantId tenantId, EntityId entityId, String key) { + return Futures.immediateFuture(Optional.ofNullable(doFindLatest(entityId, key))); + } + @Override public ListenableFuture findLatest(TenantId tenantId, EntityId entityId, String key) { - return getFindLatestFuture(entityId, key); + TsKvEntry latest = doFindLatest(entityId, key); + if (latest == null) { + latest = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(key, null)); + } + return Futures.immediateFuture(latest); } @Override @@ -195,43 +204,41 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme ReadTsKvQueryResult::getData, MoreExecutors.directExecutor()); } - protected ListenableFuture getFindLatestFuture(EntityId entityId, String key) { + protected TsKvEntry doFindLatest(EntityId entityId, String key) { TsKvLatestCompositeKey compositeKey = new TsKvLatestCompositeKey( entityId.getId(), getOrSaveKeyId(key)); Optional entry = tsKvLatestRepository.findById(compositeKey); - TsKvEntry result; if (entry.isPresent()) { TsKvLatestEntity tsKvLatestEntity = entry.get(); tsKvLatestEntity.setStrKey(key); - result = DaoUtil.getData(tsKvLatestEntity); + return DaoUtil.getData(tsKvLatestEntity); } else { - result = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(key, null)); + return null; } - return Futures.immediateFuture(result); } protected ListenableFuture getRemoveLatestFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { - ListenableFuture latestFuture = getFindLatestFuture(entityId, query.getKey()); + TsKvEntry latest = doFindLatest(entityId, query.getKey()); - ListenableFuture booleanFuture = Futures.transform(latestFuture, tsKvEntry -> { - long ts = tsKvEntry.getTs(); - return ts > query.getStartTs() && ts <= query.getEndTs(); - }, service); + if (latest == null) { + return Futures.immediateFuture(new TsKvLatestRemovingResult(query.getKey(), false)); + } - ListenableFuture removedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> { - if (isRemove) { - TsKvLatestEntity latestEntity = new TsKvLatestEntity(); - latestEntity.setEntityId(entityId.getId()); - latestEntity.setKey(getOrSaveKeyId(query.getKey())); - return service.submit(() -> { - tsKvLatestRepository.delete(latestEntity); - return true; - }); - } - return Futures.immediateFuture(false); - }, service); + long ts = latest.getTs(); + ListenableFuture removedLatestFuture; + if (ts > query.getStartTs() && ts <= query.getEndTs()) { + TsKvLatestEntity latestEntity = new TsKvLatestEntity(); + latestEntity.setEntityId(entityId.getId()); + latestEntity.setKey(getOrSaveKeyId(query.getKey())); + removedLatestFuture = service.submit(() -> { + tsKvLatestRepository.delete(latestEntity); + return true; + }); + } else { + removedLatestFuture = Futures.immediateFuture(false); + } return Futures.transformAsync(removedLatestFuture, isRemoved -> { if (isRemoved && query.getRewriteLatestIfDeleted()) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/latest/sql/SqlLatestInsertTsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/latest/sql/SqlLatestInsertTsRepository.java index 451ba29987..087f5389da 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/latest/sql/SqlLatestInsertTsRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/latest/sql/SqlLatestInsertTsRepository.java @@ -24,6 +24,7 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity; import org.thingsboard.server.dao.sqlts.insert.AbstractInsertRepository; import org.thingsboard.server.dao.sqlts.insert.latest.InsertLatestTsRepository; +import org.thingsboard.server.dao.util.SqlDao; import org.thingsboard.server.dao.util.SqlTsLatestAnyDao; import java.sql.PreparedStatement; @@ -36,6 +37,7 @@ import java.util.List; @SqlTsLatestAnyDao @Repository @Transactional +@SqlDao public class SqlLatestInsertTsRepository extends AbstractInsertRepository implements InsertLatestTsRepository { @Value("${sql.ts_latest.update_by_latest_ts:true}") diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java index 805e5e4f4f..87a62d356f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java @@ -15,23 +15,148 @@ */ package org.thingsboard.server.dao.sqlts.insert.sql; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.dao.timeseries.SqlPartition; -import org.thingsboard.server.dao.util.SqlTsDao; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; @Repository -@Transactional +@Slf4j public class SqlPartitioningRepository { @PersistenceContext private EntityManager entityManager; + @Autowired + private JdbcTemplate jdbcTemplate; + + private static final String SELECT_PARTITIONS_STMT = "SELECT tablename from pg_tables WHERE schemaname = 'public' and tablename like concat(?, '_%')"; + + private static final int PSQL_VERSION_14 = 140000; + private volatile Integer currentServerVersion; + + private final Map> tablesPartitions = new ConcurrentHashMap<>(); + private final ReentrantLock partitionCreationLock = new ReentrantLock(); + + @Transactional public void save(SqlPartition partition) { entityManager.createNativeQuery(partition.getQuery()).executeUpdate(); } + @Transactional + public void createPartitionIfNotExists(String table, long entityTs, long partitionDurationMs) { + long partitionStartTs = calculatePartitionStartTime(entityTs, partitionDurationMs); + Map partitions = tablesPartitions.computeIfAbsent(table, t -> new ConcurrentHashMap<>()); + if (!partitions.containsKey(partitionStartTs)) { + SqlPartition partition = new SqlPartition(table, partitionStartTs, partitionStartTs + partitionDurationMs, Long.toString(partitionStartTs)); + partitionCreationLock.lock(); + try { + if (partitions.containsKey(partitionStartTs)) return; + log.trace("Saving partition: {}", partition); + save(partition); + log.trace("Adding partition to map: {}", partition); + partitions.put(partition.getStart(), partition); + } catch (RuntimeException e) { + log.trace("Error occurred during partition save:", e); + String msg = ExceptionUtils.getRootCauseMessage(e); + if (msg.contains("would overlap partition")) { + log.warn("Couldn't save {} partition for {}, data will be saved to the default partition. SQL error: {}", + partition.getPartitionDate(), table, msg); + partitions.put(partition.getStart(), partition); + } else { + throw e; + } + } finally { + partitionCreationLock.unlock(); + } + } + } + + public void dropPartitionsBefore(String table, long ts, long partitionDurationMs) { + List partitions = fetchPartitions(table); + for (Long partitionStartTime : partitions) { + long partitionEndTime = partitionStartTime + partitionDurationMs; + if (partitionEndTime < ts) { + log.info("[{}] Detaching expired partition: [{}-{}]", table, partitionStartTime, partitionEndTime); + boolean success = detachAndDropPartition(table, partitionStartTime); + if (success) { + log.info("[{}] Detached expired partition: {}", table, partitionStartTime); + } + } else { + log.debug("[{}] Skipping valid partition: {}", table, partitionStartTime); + } + } + } + + public void cleanupPartitionsCache(String table, long expTime, long partitionDurationMs) { + Map partitions = tablesPartitions.get(table); + if (partitions == null) return; + partitions.keySet().removeIf(startTime -> (startTime + partitionDurationMs) < expTime); + } + + private boolean detachAndDropPartition(String table, long partitionTs) { + Map cachedPartitions = tablesPartitions.get(table); + if (cachedPartitions != null) cachedPartitions.remove(partitionTs); + + String tablePartition = table + "_" + partitionTs; + String detachPsqlStmtStr = "ALTER TABLE " + table + " DETACH PARTITION " + tablePartition; + if (getCurrentServerVersion() >= PSQL_VERSION_14) { + detachPsqlStmtStr += " CONCURRENTLY"; + } + + String dropStmtStr = "DROP TABLE " + tablePartition; + try { + jdbcTemplate.execute(detachPsqlStmtStr); + jdbcTemplate.execute(dropStmtStr); + return true; + } catch (DataAccessException e) { + log.error("[{}] Error occurred trying to detach and drop the partition {} ", table, partitionTs, e); + } + return false; + } + + public List fetchPartitions(String table) { + List partitions = new ArrayList<>(); + List partitionsTables = jdbcTemplate.queryForList(SELECT_PARTITIONS_STMT, String.class, table); + for (String partitionTableName : partitionsTables) { + String partitionTsStr = partitionTableName.substring(table.length() + 1); + try { + partitions.add(Long.parseLong(partitionTsStr)); + } catch (NumberFormatException nfe) { + log.warn("Failed to parse table name: {}", partitionTableName); + } + } + return partitions; + } + + public long calculatePartitionStartTime(long ts, long partitionDuration) { + return ts - (ts % partitionDuration); + } + + private synchronized int getCurrentServerVersion() { + if (currentServerVersion == null) { + try { + currentServerVersion = jdbcTemplate.queryForObject("SELECT current_setting('server_version_num')", Integer.class); + } catch (Exception e) { + log.warn("Error occurred during fetch of the server version", e); + } + if (currentServerVersion == null) { + currentServerVersion = 0; + } + } + return currentServerVersion; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/AbstractCassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/AbstractCassandraBaseTimeseriesDao.java index be960f4af8..d193bbf62d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/AbstractCassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/AbstractCassandraBaseTimeseriesDao.java @@ -88,14 +88,26 @@ public abstract class AbstractCassandraBaseTimeseriesDao extends CassandraAbstra protected TsKvEntry convertResultToTsKvEntry(String key, Row row) { if (row != null) { - Optional foundKeyOpt = getKey(row); - long ts = row.getLong(ModelConstants.TS_COLUMN); - return new BasicTsKvEntry(ts, toKvEntry(row, foundKeyOpt.orElse(key))); + return getBasicTsKvEntry(key, row); } else { return new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(key, null)); } } + protected Optional convertResultToTsKvEntryOpt(String key, Row row) { + if (row != null) { + return Optional.of(getBasicTsKvEntry(key, row)); + } else { + return Optional.empty(); + } + } + + private BasicTsKvEntry getBasicTsKvEntry(String key, Row row) { + Optional foundKeyOpt = getKey(row); + long ts = row.getLong(ModelConstants.TS_COLUMN); + return new BasicTsKvEntry(ts, toKvEntry(row, foundKeyOpt.orElse(key))); + } + private Optional getKey(Row row){ try{ return Optional.ofNullable(row.getString(ModelConstants.KEY_COLUMN)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index b4cb27cb53..c8a5076c65 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -47,6 +47,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.StringUtils.isBlank; @@ -117,6 +118,12 @@ public class BaseTimeseriesService implements TimeseriesService { }, MoreExecutors.directExecutor()); } + @Override + public ListenableFuture> findLatest(TenantId tenantId, EntityId entityId, String key) { + validate(entityId); + return timeseriesLatestDao.findLatestOpt(tenantId, entityId, key); + } + @Override public ListenableFuture> findLatest(TenantId tenantId, EntityId entityId, Collection keys) { validate(entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java index 2b3d62712f..4fb5be7dea 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java @@ -59,15 +59,24 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes private PreparedStatement findLatestStmt; private PreparedStatement findAllLatestStmt; + @Override + public ListenableFuture> findLatestOpt(TenantId tenantId, EntityId entityId, String key) { + return findLatest(tenantId, entityId, key, rs -> convertResultToTsKvEntryOpt(key, rs.one())); + } + @Override public ListenableFuture findLatest(TenantId tenantId, EntityId entityId, String key) { + return findLatest(tenantId, entityId, key, rs -> convertResultToTsKvEntry(key, rs.one())); + } + + private ListenableFuture findLatest(TenantId tenantId, EntityId entityId, String key, java.util.function.Function function) { BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(getFindLatestStmt().bind()); stmtBuilder.setString(0, entityId.getEntityType().name()); stmtBuilder.setUuid(1, entityId.getId()); stmtBuilder.setString(2, key); BoundStatement stmt = stmtBuilder.build(); log.debug(GENERATED_QUERY_FOR_ENTITY_TYPE_AND_ENTITY_ID, stmt, entityId.getEntityType(), entityId.getId()); - return getFuture(executeAsyncRead(tenantId, stmt), rs -> convertResultToTsKvEntry(key, rs.one())); + return getFuture(executeAsyncRead(tenantId, stmt), function); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java index d24a229766..06459b9df3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java @@ -24,9 +24,20 @@ import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvLatestRemovingResult; import java.util.List; +import java.util.Optional; public interface TimeseriesLatestDao { + /** + * Optional TsKvEntry if the value is present in the DB + * + */ + ListenableFuture> findLatestOpt(TenantId tenantId, EntityId entityId, String key); + + /** + * Returns new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(key, null)) if the value is NOT present in the DB + * + */ ListenableFuture findLatest(TenantId tenantId, EntityId entityId, String key); ListenableFuture> findAllLatest(TenantId tenantId, EntityId entityId); diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index 80a5b03b92..34862e5af3 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -48,7 +48,7 @@ CREATE INDEX IF NOT EXISTS idx_asset_type ON asset(tenant_id, type); CREATE INDEX IF NOT EXISTS idx_attribute_kv_by_key_and_last_update_ts ON attribute_kv(entity_id, attribute_key, last_update_ts desc); -CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time); +CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time DESC); CREATE INDEX IF NOT EXISTS idx_rpc_tenant_id_device_id ON rpc(tenant_id, device_id); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index dd26724b46..51df863ae5 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -74,7 +74,7 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( ); CREATE TABLE IF NOT EXISTS audit_log ( - id uuid NOT NULL CONSTRAINT audit_log_pkey PRIMARY KEY, + id uuid NOT NULL, created_time bigint NOT NULL, tenant_id uuid, customer_id uuid, @@ -87,7 +87,7 @@ CREATE TABLE IF NOT EXISTS audit_log ( action_data varchar(1000000), action_status varchar(255), action_failure_details varchar(1000000) -); +) PARTITION BY RANGE (created_time); CREATE TABLE IF NOT EXISTS attribute_kv ( entity_type varchar(255), diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/DataValidatorTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/DataValidatorTest.java new file mode 100644 index 0000000000..c64b418fa0 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/DataValidatorTest.java @@ -0,0 +1,63 @@ +/** + * Copyright © 2016-2022 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.server.dao.service; + +import org.junit.Test; +import org.thingsboard.server.dao.exception.DataValidationException; + +public class DataValidatorTest { + + @Test + public void validateEmail() { + String email = "aZ1_!#$%&'*+/=?`{|}~^.-@mail.io"; + DataValidator.validateEmail(email); + } + + @Test(expected = DataValidationException.class) + public void validateInvalidEmail1() { + String email = "test:1@mail.io"; + DataValidator.validateEmail(email); + } + @Test(expected = DataValidationException.class) + public void validateInvalidEmail2() { + String email = "test()1@mail.io"; + DataValidator.validateEmail(email); + } + + @Test(expected = DataValidationException.class) + public void validateInvalidEmail3() { + String email = "test[]1@mail.io"; + DataValidator.validateEmail(email); + } + + @Test(expected = DataValidationException.class) + public void validateInvalidEmail4() { + String email = "test\\1@mail.io"; + DataValidator.validateEmail(email); + } + + @Test(expected = DataValidationException.class) + public void validateInvalidEmail5() { + String email = "test\"1@mail.io"; + DataValidator.validateEmail(email); + } + + @Test(expected = DataValidationException.class) + public void validateInvalidEmail6() { + String email = "test<>1@mail.io"; + DataValidator.validateEmail(email); + } +} \ No newline at end of file diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/NoXssValidatorTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/NoXssValidatorTest.java index c4ef964883..36eb76edb5 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/NoXssValidatorTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/NoXssValidatorTest.java @@ -42,7 +42,7 @@ public class NoXssValidatorTest { "

Link!!!

1221", "

Please log in to proceed

Username:

Password:



", " ", - "123 bebe", + "123 bebe" }) public void testIsNotValid(String stringWithXss) { boolean isValid = validator.isValid(stringWithXss, mock(ConstraintValidatorContext.class)); diff --git a/msa/js-executor/api/jsExecutor.models.ts b/msa/js-executor/api/jsExecutor.models.ts index db2ced52c4..7a6b53cd8a 100644 --- a/msa/js-executor/api/jsExecutor.models.ts +++ b/msa/js-executor/api/jsExecutor.models.ts @@ -16,8 +16,9 @@ export interface TbMessage { - scriptIdMSB: string; - scriptIdLSB: string; + scriptIdMSB: string; // deprecated + scriptIdLSB: string; // deprecated + scriptHash: string; } export interface RemoteJsRequest { diff --git a/msa/js-executor/api/jsInvokeMessageProcessor.ts b/msa/js-executor/api/jsInvokeMessageProcessor.ts index 0a101775e4..668cd61f50 100644 --- a/msa/js-executor/api/jsInvokeMessageProcessor.ts +++ b/msa/js-executor/api/jsInvokeMessageProcessor.ts @@ -18,7 +18,7 @@ import config from 'config'; import { _logger } from '../config/logger'; import { JsExecutor, TbScript } from './jsExecutor'; import { performance } from 'perf_hooks'; -import { isString, parseJsErrorDetails, toUUIDString, UUIDFromBuffer, UUIDToBits } from './utils'; +import { isString, parseJsErrorDetails, toUUIDString, UUIDFromBuffer, UUIDToBits, isNotUUID } from './utils'; import { IQueue } from '../queue/queue.models'; import { JsCompileRequest, @@ -36,6 +36,7 @@ import Long from 'long'; const COMPILATION_ERROR = 0; const RUNTIME_ERROR = 1; const TIMEOUT_ERROR = 2; +const NOT_FOUND_ERROR = 3; const statFrequency = Number(config.get('script.stat_print_frequency')); const scriptBodyTraceFrequency = Number(config.get('script.script_body_trace_frequency')); @@ -43,6 +44,7 @@ const useSandbox = config.get('script.use_sandbox') === 'true'; const maxActiveScripts = Number(config.get('script.max_active_scripts')); const slowQueryLogMs = Number(config.get('script.slow_query_log_ms')); const slowQueryLogBody = config.get('script.slow_query_log_body') === 'true'; +const maxResultSize = Number(config.get('js.max_result_size')); export class JsInvokeMessageProcessor { @@ -128,7 +130,12 @@ export class JsInvokeMessageProcessor { processCompileRequest(requestId: string, responseTopic: string, headers: any, compileRequest: JsCompileRequest) { const scriptId = JsInvokeMessageProcessor.getScriptId(compileRequest); this.logger.debug('[%s] Processing compile request, scriptId: [%s]', requestId, scriptId); - + if (this.scriptMap.has(scriptId)) { + const compileResponse = JsInvokeMessageProcessor.createCompileResponse(scriptId, true); + this.logger.debug('[%s] Script was already compiled, scriptId: [%s]', requestId, scriptId); + this.sendResponse(requestId, responseTopic, headers, scriptId, compileResponse); + return; + } this.executor.compileScript(compileRequest.scriptBody).then( (script) => { this.cacheScript(scriptId, script); @@ -164,9 +171,19 @@ export class JsInvokeMessageProcessor { (script) => { this.executor.executeScript(script, invokeRequest.args, invokeRequest.timeout).then( (result) => { - const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse(result, true); - this.logger.debug('[%s] Sending success invoke response, scriptId: [%s]', requestId, scriptId); - this.sendResponse(requestId, responseTopic, headers, scriptId, undefined, invokeResponse); + if (result.length <= maxResultSize) { + const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse(result, true); + this.logger.debug('[%s] Sending success invoke response, scriptId: [%s]', requestId, scriptId); + this.sendResponse(requestId, responseTopic, headers, scriptId, undefined, invokeResponse); + } else { + const err = { + name: 'Error', + message: 'script invocation result exceeds maximum allowed size of ' + maxResultSize + ' symbols' + } + const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse("", false, RUNTIME_ERROR, err); + this.logger.debug('[%s] Script invocation result exceeds maximum allowed size of %s symbols, scriptId: [%s]', requestId, maxResultSize, scriptId); + this.sendResponse(requestId, responseTopic, headers, scriptId, undefined, invokeResponse); + } }, (err: any) => { let errorCode; @@ -182,8 +199,12 @@ export class JsInvokeMessageProcessor { ) }, (err: any) => { - const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse("", false, COMPILATION_ERROR, err); - this.logger.debug('[%s] Sending failed invoke response, scriptId: [%s], errorCode: [%s]', requestId, scriptId, COMPILATION_ERROR); + let errorCode = COMPILATION_ERROR; + if (err?.name === 'script body not found') { + errorCode = NOT_FOUND_ERROR; + } + const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse("", false, errorCode, err); + this.logger.debug('[%s] Sending failed invoke response, scriptId: [%s], errorCode: [%s]', requestId, scriptId, errorCode); this.sendResponse(requestId, responseTopic, headers, scriptId, undefined, invokeResponse); } ); @@ -211,7 +232,7 @@ export class JsInvokeMessageProcessor { const remoteResponse = JsInvokeMessageProcessor.createRemoteResponse(requestId, compileResponse, invokeResponse, releaseResponse); const rawResponse = Buffer.from(JSON.stringify(remoteResponse), 'utf8'); this.logger.debug('[%s] Sending response to queue, scriptId: [%s]', requestId, scriptId); - this.producer.send(responseTopic, scriptId, rawResponse, headers).then( + this.producer.send(responseTopic, requestId, rawResponse, headers).then( () => { this.logger.debug('[%s] Response sent to queue, took [%s]ms, scriptId: [%s]', requestId, (performance.now() - tStartSending), scriptId); }, @@ -231,7 +252,7 @@ export class JsInvokeMessageProcessor { if (script) { self.incrementUseScriptId(scriptId); resolve(script); - } else { + } else if (scriptBody) { const startTime = performance.now(); self.executor.compileScript(scriptBody).then( (compiledScript) => { @@ -244,6 +265,12 @@ export class JsInvokeMessageProcessor { reject(err); } ); + } else { + const err = { + name: 'script body not found', + message: '' + } + reject(err); } }); } @@ -274,14 +301,26 @@ export class JsInvokeMessageProcessor { } private static createCompileResponse(scriptId: string, success: boolean, errorCode?: number, err?: any): JsCompileResponse { - const scriptIdBits = UUIDToBits(scriptId); - return { - errorCode: errorCode, - success: success, - errorDetails: parseJsErrorDetails(err), - scriptIdMSB: scriptIdBits[0], - scriptIdLSB: scriptIdBits[1] - }; + if (isNotUUID(scriptId)) { + return { + errorCode: errorCode, + success: success, + errorDetails: parseJsErrorDetails(err), + scriptIdMSB: "0", + scriptIdLSB: "0", + scriptHash: scriptId + }; + } else { // this is for backward compatibility (to be able to work with tb-node of previous version) - todo: remove in the next release + let scriptIdBits = UUIDToBits(scriptId); + return { + errorCode: errorCode, + success: success, + errorDetails: parseJsErrorDetails(err), + scriptIdMSB: scriptIdBits[0], + scriptIdLSB: scriptIdBits[1], + scriptHash: "" + }; + } } private static createInvokeResponse(result: string, success: boolean, errorCode?: number, err?: any): JsInvokeResponse { @@ -294,16 +333,26 @@ export class JsInvokeMessageProcessor { } private static createReleaseResponse(scriptId: string, success: boolean): JsReleaseResponse { - const scriptIdBits = UUIDToBits(scriptId); - return { - success: success, - scriptIdMSB: scriptIdBits[0], - scriptIdLSB: scriptIdBits[1] - }; + if (isNotUUID(scriptId)) { + return { + success: success, + scriptIdMSB: "0", + scriptIdLSB: "0", + scriptHash: scriptId, + }; + } else { // todo: remove in the next release + let scriptIdBits = UUIDToBits(scriptId); + return { + success: success, + scriptIdMSB: scriptIdBits[0], + scriptIdLSB: scriptIdBits[1], + scriptHash: "" + } + } } private static getScriptId(request: TbMessage): string { - return toUUIDString(request.scriptIdMSB, request.scriptIdLSB); + return request.scriptHash ? request.scriptHash : toUUIDString(request.scriptIdMSB, request.scriptIdLSB); } private incrementUseScriptId(scriptId: string) { diff --git a/msa/js-executor/api/utils.ts b/msa/js-executor/api/utils.ts index 361025f806..58fec28b0b 100644 --- a/msa/js-executor/api/utils.ts +++ b/msa/js-executor/api/utils.ts @@ -58,3 +58,7 @@ export function parseJsErrorDetails(err: any): string | undefined { } return details; } + +export function isNotUUID(candidate: string) { + return candidate.length != 36 || !candidate.includes('-'); +} diff --git a/msa/js-executor/config/custom-environment-variables.yml b/msa/js-executor/config/custom-environment-variables.yml index d408b14136..b9c24c8d8d 100644 --- a/msa/js-executor/config/custom-environment-variables.yml +++ b/msa/js-executor/config/custom-environment-variables.yml @@ -20,6 +20,7 @@ http_port: "HTTP_PORT" # /livenessProbe js: response_poll_interval: "REMOTE_JS_RESPONSE_POLL_INTERVAL_MS" + max_result_size: "JS_MAX_RESULT_SIZE" kafka: bootstrap: diff --git a/msa/js-executor/config/default.yml b/msa/js-executor/config/default.yml index 32163ea01e..64829ef792 100644 --- a/msa/js-executor/config/default.yml +++ b/msa/js-executor/config/default.yml @@ -20,6 +20,7 @@ http_port: "8888" # /livenessProbe js: response_poll_interval: "25" + max_result_size: "300000" kafka: bootstrap: diff --git a/msa/js-executor/queue/awsSqsTemplate.ts b/msa/js-executor/queue/awsSqsTemplate.ts index 259d285cf2..31de1ae73f 100644 --- a/msa/js-executor/queue/awsSqsTemplate.ts +++ b/msa/js-executor/queue/awsSqsTemplate.ts @@ -123,10 +123,10 @@ export class AwsSqsTemplate implements IQueue { this.timer = setTimeout(() => {this.getAndProcessMessage(messageProcessor, params)}, this.pollInterval); } - async send(responseTopic: string, scriptId: string, rawResponse: Buffer, headers: any): Promise { + async send(responseTopic: string, msgKey: string, rawResponse: Buffer, headers: any): Promise { let msgBody = JSON.stringify( { - key: scriptId, + key: msgKey, data: [...rawResponse], headers: headers }); diff --git a/msa/js-executor/queue/kafkaTemplate.ts b/msa/js-executor/queue/kafkaTemplate.ts index 51fa6e291b..7c34d99889 100644 --- a/msa/js-executor/queue/kafkaTemplate.ts +++ b/msa/js-executor/queue/kafkaTemplate.ts @@ -149,12 +149,11 @@ export class KafkaTemplate implements IQueue { }); } - async send(responseTopic: string, scriptId: string, rawResponse: Buffer, headers: any): Promise { - this.logger.debug('Pending queue response, scriptId: [%s]', scriptId); + async send(responseTopic: string, msgKey: string, rawResponse: Buffer, headers: any): Promise { const message = { topic: responseTopic, messages: [{ - key: scriptId, + key: msgKey, value: rawResponse, headers: headers.data }] diff --git a/msa/js-executor/queue/pubSubTemplate.ts b/msa/js-executor/queue/pubSubTemplate.ts index eff35017ba..9e8ee52b8b 100644 --- a/msa/js-executor/queue/pubSubTemplate.ts +++ b/msa/js-executor/queue/pubSubTemplate.ts @@ -80,7 +80,7 @@ export class PubSubTemplate implements IQueue { subscription.on('message', messageHandler); } - async send(responseTopic: string, scriptId: string, rawResponse: Buffer, headers: any): Promise { + async send(responseTopic: string, msgKey: string, rawResponse: Buffer, headers: any): Promise { if (!(this.subscriptions.includes(responseTopic) && this.topics.includes(this.requestTopic))) { await this.createTopic(this.requestTopic); await this.createSubscription(this.requestTopic); @@ -88,7 +88,7 @@ export class PubSubTemplate implements IQueue { let data = JSON.stringify( { - key: scriptId, + key: msgKey, data: [...rawResponse], headers: headers }); diff --git a/msa/js-executor/queue/queue.models.ts b/msa/js-executor/queue/queue.models.ts index a86dc8fd1d..36932a5ee5 100644 --- a/msa/js-executor/queue/queue.models.ts +++ b/msa/js-executor/queue/queue.models.ts @@ -17,6 +17,6 @@ export interface IQueue { name: string; init(): Promise; - send(responseTopic: string, scriptId: string, rawResponse: Buffer, headers: any): Promise; + send(responseTopic: string, msgKey: string, rawResponse: Buffer, headers: any): Promise; destroy(): Promise; } diff --git a/msa/js-executor/queue/rabbitmqTemplate.ts b/msa/js-executor/queue/rabbitmqTemplate.ts index ccd3cef54b..f4fe51a0ae 100644 --- a/msa/js-executor/queue/rabbitmqTemplate.ts +++ b/msa/js-executor/queue/rabbitmqTemplate.ts @@ -65,7 +65,7 @@ export class RabbitMqTemplate implements IQueue { }) } - async send(responseTopic: string, scriptId: string, rawResponse: Buffer, headers: any): Promise { + async send(responseTopic: string, msgKey: string, rawResponse: Buffer, headers: any): Promise { if (!this.topics.includes(responseTopic)) { await this.createQueue(responseTopic); @@ -74,7 +74,7 @@ export class RabbitMqTemplate implements IQueue { let data = JSON.stringify( { - key: scriptId, + key: msgKey, data: [...rawResponse], headers: headers }); diff --git a/msa/js-executor/queue/serviceBusTemplate.ts b/msa/js-executor/queue/serviceBusTemplate.ts index 76d87e8068..d2abacd289 100644 --- a/msa/js-executor/queue/serviceBusTemplate.ts +++ b/msa/js-executor/queue/serviceBusTemplate.ts @@ -82,7 +82,7 @@ export class ServiceBusTemplate implements IQueue { this.receiver.subscribe({processMessage: messageHandler, processError: errorHandler}) } - async send(responseTopic: string, scriptId: string, rawResponse: Buffer, headers: any): Promise { + async send(responseTopic: string, msgKey: string, rawResponse: Buffer, headers: any): Promise { if (!this.queues.includes(this.requestTopic)) { await this.createQueueIfNotExist(this.requestTopic); this.queues.push(this.requestTopic); @@ -96,7 +96,7 @@ export class ServiceBusTemplate implements IQueue { } let data = { - key: scriptId, + key: msgKey, data: [...rawResponse], headers: headers }; diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index 30358d97cb..f204a6822f 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -38,7 +38,7 @@ tb-postgres tb-cassandra /usr/share/${pkg.name} - 3.3.3 + 3.4.2 diff --git a/pom.xml b/pom.xml index 347874faef..1c5dea9f5c 100755 --- a/pom.xml +++ b/pom.xml @@ -137,6 +137,7 @@ 1.12 3.0.0 6.1.0.202203080745-r + 0.4.8 1.0.0 @@ -1213,7 +1214,6 @@ com.jayway.jsonpath json-path ${json-path.version} - test com.jayway.jsonpath @@ -1911,6 +1911,11 @@ org.eclipse.jgit.ssh.apache ${jgit.version} + + net.objecthunter + exp4j + ${exp4j.version} + diff --git a/pull_request_template.md b/pull_request_template.md index 6e7c31967e..21362429dc 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -6,6 +6,7 @@ Put your PR description here instead of this sentence. - [ ] You have reviewed the guidelines [document](https://docs.google.com/document/d/1wqcOafLx5hth8SAg4dqV_LV3un3m5WYR8RdTJ4MbbUM/edit?usp=sharing). - [ ] PR name contains fix version. For example, "[3.3.4] Hotfix of some UI component" or "[3.4] New Super Feature". +- [ ] The [milestone](https://docs.github.com/en/issues/using-labels-and-milestones-to-track-work/about-milestones) is specified and corresponds to fix version. - [ ] Description references specific [issue](https://github.com/thingsboard/thingsboard/issues). - [ ] Description contains human-readable scope of changes. - [ ] Description contains brief notes about what needs to be added to the documentation. diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java index 7a316bb78e..dbee45c230 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java @@ -16,6 +16,7 @@ package org.thingsboard.rule.engine.api; import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -31,6 +32,8 @@ import java.util.List; */ public interface RuleEngineTelemetryService { + ListenableFuture saveAndNotify(TenantId tenantId, EntityId entityId, TsKvEntry ts); + void saveAndNotify(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback); void saveAndNotify(TenantId tenantId, CustomerId id, EntityId entityId, List ts, long ttl, FutureCallback callback); @@ -43,6 +46,14 @@ public interface RuleEngineTelemetryService { void saveLatestAndNotify(TenantId tenantId, EntityId entityId, List ts, FutureCallback callback); + ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value); + + ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, String value); + + ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, double value); + + ListenableFuture saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, boolean value); + void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value, FutureCallback callback); void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, String value, FutureCallback callback); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index 5892633649..01f61f1e4f 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleNode; @@ -61,6 +62,7 @@ import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.user.UserService; +import java.util.List; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -182,6 +184,10 @@ public interface TbContext { // TODO: Does this changes the message? TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action); + TbMsg attributesUpdatedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List attributes); + + TbMsg attributesDeletedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List keys); + void onEdgeEventUpdate(TenantId tenantId, EdgeId edgeId); /* diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 439ed41859..996063823b 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -121,6 +121,10 @@ javax.mail provided + + net.objecthunter + exp4j + org.springframework.boot spring-boot-starter-test @@ -139,10 +143,12 @@ org.mock-server mockserver-netty + test org.mock-server mockserver-client-java + test @@ -160,6 +166,10 @@ test + + com.jayway.jsonpath + json-path + diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index fd69303501..b9f4b7085e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -21,6 +21,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.thingsboard.common.util.CollectionsUtil; import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; @@ -74,6 +75,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { if (DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) || DataConstants.ATTRIBUTES_DELETED.equals(msg.getType()) || DataConstants.ACTIVITY_EVENT.equals(msg.getType()) || + DataConstants.INACTIVITY_EVENT.equals(msg.getType()) || SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType())) { if (!msg.getMetaData().getData().isEmpty()) { long now = System.currentTimeMillis(); @@ -89,25 +91,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { long startTime = entityView.getStartTimeMs(); long endTime = entityView.getEndTimeMs(); if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) { - if (DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) || - DataConstants.ACTIVITY_EVENT.equals(msg.getType()) || - SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType())) { - Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())); - List filteredAttributes = - attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr.getKey(), entityView)).collect(Collectors.toList()); - ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), entityView.getId(), scope, filteredAttributes, - new FutureCallback() { - @Override - public void onSuccess(@Nullable Void result) { - transformAndTellNext(ctx, msg, entityView); - } - - @Override - public void onFailure(Throwable t) { - ctx.tellFailure(msg, t); - } - }); - } else if (DataConstants.ATTRIBUTES_DELETED.equals(msg.getType())) { + if (DataConstants.ATTRIBUTES_DELETED.equals(msg.getType())) { List attributes = new ArrayList<>(); for (JsonElement element : new JsonParser().parse(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray()) { if (element.isJsonPrimitive()) { @@ -120,9 +104,15 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { List filteredAttributes = attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr, entityView)).collect(Collectors.toList()); if (!filteredAttributes.isEmpty()) { - ctx.getAttributesService().removeAll(ctx.getTenantId(), entityView.getId(), scope, filteredAttributes); - transformAndTellNext(ctx, msg, entityView); + ctx.getTelemetryService().deleteAndNotify(ctx.getTenantId(), entityView.getId(), scope, filteredAttributes, + getFutureCallback(ctx, msg, entityView)); } + } else { + Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())); + List filteredAttributes = + attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr.getKey(), entityView)).collect(Collectors.toList()); + ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), entityView.getId(), scope, filteredAttributes, + getFutureCallback(ctx, msg, entityView)); } } } @@ -137,6 +127,21 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { } } + @NotNull + private FutureCallback getFutureCallback(TbContext ctx, TbMsg msg, EntityView entityView) { + return new FutureCallback() { + @Override + public void onSuccess(@Nullable Void result) { + transformAndTellNext(ctx, msg, entityView); + } + + @Override + public void onFailure(Throwable t) { + ctx.tellFailure(msg, t); + } + }; + } + private void transformAndTellNext(TbContext ctx, TbMsg msg, EntityView entityView) { ctx.enqueueForTellNext(ctx.newMsg(msg.getQueueName(), msg.getType(), entityView.getId(), msg.getCustomerId(), msg.getMetaData(), msg.getData()), SUCCESS); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java index 62e44bb50e..0cd70c0b4c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java @@ -36,7 +36,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType; relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "RPC Queued", "RPC Sent", "RPC Delivered", "RPC Successful", "RPC Timeout", "RPC Expired", "RPC Failed", "RPC Deleted", "Activity Event", "Inactivity Event", "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned", "Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Other", "Entity Assigned From Tenant", "Entity Assigned To Tenant", - "Timeseries Updated", "Timeseries Deleted"}, + "Relation Added or Updated", "Relation Deleted", "All Relations Deleted", "Timeseries Updated", "Timeseries Deleted"}, nodeDescription = "Route incoming messages by Message Type", nodeDetails = "Sends messages with message types \"Post attributes\", \"Post telemetry\", \"RPC Request\" etc. via corresponding chain, otherwise Other chain is used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, @@ -111,6 +111,12 @@ public class TbMsgTypeSwitchNode implements TbNode { relationType = "RPC Failed"; } else if (msg.getType().equals(DataConstants.RPC_DELETED)) { relationType = "RPC Deleted"; + } else if (msg.getType().equals(DataConstants.RELATION_ADD_OR_UPDATE)) { + relationType = "Relation Added or Updated"; + } else if (msg.getType().equals(DataConstants.RELATION_DELETED)) { + relationType = "Relation Deleted"; + } else if (msg.getType().equals(DataConstants.RELATIONS_DELETED)) { + relationType = "All Relations Deleted"; } else { relationType = "Other"; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgument.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgument.java new file mode 100644 index 0000000000..db1300722a --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgument.java @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2022 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.math; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TbMathArgument { + + private String name; + private TbMathArgumentType type; + private String key; + private String attributeScope; + private Double defaultValue; + + public TbMathArgument(TbMathArgumentType type, String key) { + this(key, type, key, null, null); + } + + public TbMathArgument(String name, TbMathArgumentType type, String key) { + this(name, type, key, null, null); + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentType.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentType.java new file mode 100644 index 0000000000..39640bb390 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentType.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2022 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.math; + +public enum TbMathArgumentType { + + ATTRIBUTE, TIME_SERIES, MESSAGE_BODY, MESSAGE_METADATA, CONSTANT; + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentValue.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentValue.java new file mode 100644 index 0000000000..c0fe5d30b5 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentValue.java @@ -0,0 +1,108 @@ +/** + * Copyright © 2016-2022 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.math; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.Getter; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.Optional; + +public class TbMathArgumentValue { + + @Getter + private final double value; + + private TbMathArgumentValue(double value) { + this.value = value; + } + + public static TbMathArgumentValue constant(TbMathArgument arg) { + return fromString(arg.getKey()); + } + + private static TbMathArgumentValue defaultOrThrow(Double defaultValue, String error) { + if (defaultValue != null) { + return new TbMathArgumentValue(defaultValue); + } + throw new RuntimeException(error); + } + + public static TbMathArgumentValue fromMessageBody(TbMathArgument arg, Optional jsonNodeOpt) { + String key = arg.getKey(); + Double defaultValue = arg.getDefaultValue(); + if (jsonNodeOpt.isEmpty()) { + return defaultOrThrow(defaultValue, "Message body is empty!"); + } + var json = jsonNodeOpt.get(); + if (!json.has(key)) { + return defaultOrThrow(defaultValue, "Message body has no '" + key + "'!"); + } + JsonNode valueNode = json.get(key); + if (valueNode.isNull()) { + return defaultOrThrow(defaultValue, "Message body has null '" + key + "'!"); + } + double value; + if (valueNode.isNumber()) { + value = valueNode.doubleValue(); + } else if (valueNode.isTextual()) { + var valueNodeText = valueNode.asText(); + if (StringUtils.isNotBlank(valueNodeText)) { + try { + value = Double.parseDouble(valueNode.asText()); + } catch (NumberFormatException ne) { + throw new RuntimeException("Can't convert value '" + valueNode.asText() + "' to double!"); + } + } else { + return defaultOrThrow(defaultValue, "Message value is empty for '" + key + "'!"); + } + } else { + throw new RuntimeException("Can't convert value '" + valueNode.toString() + "' to double!"); + } + return new TbMathArgumentValue(value); + } + + public static TbMathArgumentValue fromMessageMetadata(TbMathArgument arg, TbMsgMetaData metaData) { + String key = arg.getKey(); + Double defaultValue = arg.getDefaultValue(); + if (metaData == null) { + return defaultOrThrow(defaultValue, "Message metadata is empty!"); + } + var value = metaData.getValue(key); + if (StringUtils.isEmpty(value)) { + return defaultOrThrow(defaultValue, "Message metadata has no '" + key + "'!"); + } + return fromString(value); + } + + public static TbMathArgumentValue fromLong(long value) { + return new TbMathArgumentValue(value); + } + + public static TbMathArgumentValue fromDouble(double value) { + return new TbMathArgumentValue(value); + } + + public static TbMathArgumentValue fromString(String value) { + try { + return new TbMathArgumentValue(Double.parseDouble(value)); + } catch (NumberFormatException ne) { + throw new RuntimeException("Can't convert value '" + value + "' to double!"); + } + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java new file mode 100644 index 0000000000..6ad0ae9352 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java @@ -0,0 +1,397 @@ +/** + * Copyright © 2016-2022 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.math; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.extern.slf4j.Slf4j; +import net.objecthunter.exp4j.Expression; +import net.objecthunter.exp4j.ExpressionBuilder; +import org.springframework.util.ConcurrentReferenceHashMap; +import org.thingsboard.common.util.DonAsynchron; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.KvEntry; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +@SuppressWarnings("UnstableApiUsage") +@Slf4j +@RuleNode( + type = ComponentType.ACTION, + name = "math function", + configClazz = TbMathNodeConfiguration.class, + nodeDescription = "Apply math function and save the result into the message and/or database", + nodeDetails = "Supports math operations like: ADD, SUB, MULT, DIV, etc and functions: SIN, COS, TAN, SEC, etc. " + + "Use 'CUSTOM' operation to specify complex math expressions." + + "

" + + "You may use constant, message field, metadata field, attribute, and latest time-series as an arguments values. " + + "The result of the function may be also stored to message field, metadata field, attribute or time-series value." + + "

" + + "Primary use case for this rule node is to take one or more values from the database and modify them based on data from the message. " + + "For example, you may increase `totalWaterConsumption` based on the `deltaWaterConsumption` reported by device." + + "

" + + "Alternative use case is the replacement of simple JS `script` nodes with more light-weight and performant implementation. " + + "For example, you may transform Fahrenheit to Celsius (C = (F - 32) / 1.8) using CUSTOM operation and expression: (x - 32) / 1.8)." + + "

" + + "The execution is synchronized in scope of message originator (e.g. device) and server node. " + + "If you have rule nodes in different rule chains, they will process messages from the same originator synchronously in the scope of the server node.", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbActionNodeMathFunctionConfig", + icon = "calculate" + +) +public class TbMathNode implements TbNode { + + private static final ConcurrentMap semaphores = new ConcurrentReferenceHashMap<>(); + private final ThreadLocal customExpression = new ThreadLocal<>(); + + private TbMathNodeConfiguration config; + private boolean msgBodyToJsonConversionRequired; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbMathNodeConfiguration.class); + var operation = config.getOperation(); + var argsCount = config.getArguments().size(); + if (argsCount < operation.getMinArgs() || argsCount > operation.getMaxArgs()) { + throw new RuntimeException("Args count: " + argsCount + " does not match operation: " + operation.name()); + } + if (TbRuleNodeMathFunctionType.CUSTOM.equals(operation)) { + if (StringUtils.isBlank(config.getCustomFunction())) { + throw new RuntimeException("Custom function is blank!"); + } else if (config.getCustomFunction().length() > 256) { + throw new RuntimeException("Custom function is too complex (length > 256)!"); + } + } + msgBodyToJsonConversionRequired = config.getArguments().stream().anyMatch(arg -> TbMathArgumentType.MESSAGE_BODY.equals(arg.getType())); + msgBodyToJsonConversionRequired = msgBodyToJsonConversionRequired || TbMathArgumentType.MESSAGE_BODY.equals(config.getResult().getType()); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) { + var originator = msg.getOriginator(); + var originatorSemaphore = semaphores.computeIfAbsent(originator, tmp -> new Semaphore(1, true)); + boolean acquired = tryAcquire(originator, originatorSemaphore); + + if (!acquired) { + ctx.tellFailure(msg, new RuntimeException("Failed to process message for originator synchronously")); + return; + } + + try { + var arguments = config.getArguments(); + Optional msgBodyOpt = convertMsgBodyIfRequired(msg); + var argumentValues = Futures.allAsList(arguments.stream() + .map(arg -> resolveArguments(ctx, msg, msgBodyOpt, arg)).collect(Collectors.toList())); + ListenableFuture resultMsgFuture = Futures.transformAsync(argumentValues, args -> + updateMsgAndDb(ctx, msg, msgBodyOpt, calculateResult(ctx, msg, args)), ctx.getDbCallbackExecutor()); + DonAsynchron.withCallback(resultMsgFuture, resultMsg -> { + try { + ctx.tellSuccess(resultMsg); + } finally { + originatorSemaphore.release(); + } + }, t -> { + try { + ctx.tellFailure(msg, t); + } finally { + originatorSemaphore.release(); + } + }, ctx.getDbCallbackExecutor()); + } catch (Throwable e) { + originatorSemaphore.release(); + log.warn("[{}] Failed to process message: {}", originator, msg, e); + throw e; + } + } + + private boolean tryAcquire(EntityId originator, Semaphore originatorSemaphore) { + boolean acquired; + try { + acquired = originatorSemaphore.tryAcquire(20, TimeUnit.SECONDS); + } catch (InterruptedException e) { + acquired = false; + log.debug("[{}] Failed to acquire semaphore", originator, e); + } + return acquired; + } + + private ListenableFuture updateMsgAndDb(TbContext ctx, TbMsg msg, Optional msgBodyOpt, double result) { + TbMathResult mathResultDef = config.getResult(); + switch (mathResultDef.getType()) { + case MESSAGE_BODY: + return Futures.immediateFuture(addToBody(msg, mathResultDef, msgBodyOpt, result)); + case MESSAGE_METADATA: + return Futures.immediateFuture(addToMeta(msg, mathResultDef, result)); + case ATTRIBUTE: + ListenableFuture attrSave = saveAttribute(ctx, msg, result, mathResultDef); + return Futures.transform(attrSave, attr -> addToBodyAndMeta(msg, msgBodyOpt, result, mathResultDef), ctx.getDbCallbackExecutor()); + case TIME_SERIES: + ListenableFuture tsSave = saveTimeSeries(ctx, msg, result, mathResultDef); + return Futures.transform(tsSave, ts -> addToBodyAndMeta(msg, msgBodyOpt, result, mathResultDef), ctx.getDbCallbackExecutor()); + default: + throw new RuntimeException("Result type is not supported: " + mathResultDef.getType() + "!"); + } + } + + private ListenableFuture saveTimeSeries(TbContext ctx, TbMsg msg, double result, TbMathResult mathResultDef) { + + return ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), msg.getOriginator(), + new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry(mathResultDef.getKey(), result))); + } + + private ListenableFuture saveAttribute(TbContext ctx, TbMsg msg, double result, TbMathResult mathResultDef) { + String attributeScope = getAttributeScope(mathResultDef.getAttributeScope()); + if (isIntegerResult(mathResultDef, config.getOperation())) { + var value = toIntValue(mathResultDef, result); + return ctx.getTelemetryService().saveAttrAndNotify( + ctx.getTenantId(), msg.getOriginator(), attributeScope, mathResultDef.getKey(), value); + } else { + var value = toDoubleValue(mathResultDef, result); + return ctx.getTelemetryService().saveAttrAndNotify( + ctx.getTenantId(), msg.getOriginator(), attributeScope, mathResultDef.getKey(), value); + } + } + + private boolean isIntegerResult(TbMathResult mathResultDef, TbRuleNodeMathFunctionType function) { + return function.isIntegerResult() || mathResultDef.getResultValuePrecision() == 0; + } + + private long toIntValue(TbMathResult mathResultDef, double value) { + return (long) value; + } + + private double toDoubleValue(TbMathResult mathResultDef, double value) { + return BigDecimal.valueOf(value).setScale(mathResultDef.getResultValuePrecision(), RoundingMode.HALF_UP).doubleValue(); + } + + private Optional convertMsgBodyIfRequired(TbMsg msg) { + Optional msgBodyOpt; + if (msgBodyToJsonConversionRequired) { + var jsonNode = JacksonUtil.toJsonNode(msg.getData()); + if (jsonNode.isObject()) { + msgBodyOpt = Optional.of((ObjectNode) jsonNode); + } else { + throw new RuntimeException("Message body is not a JSON object!"); + } + } else { + msgBodyOpt = Optional.empty(); + } + return msgBodyOpt; + } + + private TbMsg addToBodyAndMeta(TbMsg msg, Optional msgBodyOpt, double result, TbMathResult mathResultDef) { + TbMsg tmpMsg = msg; + if (mathResultDef.isAddToBody()) { + tmpMsg = addToBody(msg, mathResultDef, msgBodyOpt, result); + } + if (mathResultDef.isAddToMetadata()) { + tmpMsg = addToMeta(msg, mathResultDef, result); + } + return tmpMsg; + } + + private TbMsg addToBody(TbMsg msg, TbMathResult mathResultDef, Optional msgBodyOpt, double result) { + ObjectNode body = msgBodyOpt.get(); + if (isIntegerResult(mathResultDef, config.getOperation())) { + body.put(mathResultDef.getKey(), toIntValue(mathResultDef, result)); + } else { + body.put(mathResultDef.getKey(), toDoubleValue(mathResultDef, result)); + } + return TbMsg.transformMsgData(msg, JacksonUtil.toString(body)); + } + + private TbMsg addToMeta(TbMsg msg, TbMathResult mathResultDef, double result) { + var md = msg.getMetaData(); + if (isIntegerResult(mathResultDef, config.getOperation())) { + md.putValue(mathResultDef.getKey(), Long.toString(toIntValue(mathResultDef, result))); + } else { + md.putValue(mathResultDef.getKey(), Double.toString(toDoubleValue(mathResultDef, result))); + } + return TbMsg.transformMsg(msg, md); + } + + private double calculateResult(TbContext ctx, TbMsg msg, List args) { + switch (config.getOperation()) { + case ADD: + return apply(args.get(0), args.get(1), Double::sum); + case SUB: + return apply(args.get(0), args.get(1), (a, b) -> a - b); + case MULT: + return apply(args.get(0), args.get(1), (a, b) -> a * b); + case DIV: + return apply(args.get(0), args.get(1), (a, b) -> a / b); + case SIN: + return apply(args.get(0), Math::sin); + case SINH: + return apply(args.get(0), Math::sinh); + case COS: + return apply(args.get(0), Math::cos); + case COSH: + return apply(args.get(0), Math::cosh); + case TAN: + return apply(args.get(0), Math::tan); + case TANH: + return apply(args.get(0), Math::tanh); + case ACOS: + return apply(args.get(0), Math::acos); + case ASIN: + return apply(args.get(0), Math::asin); + case ATAN: + return apply(args.get(0), Math::atan); + case ATAN2: + return apply(args.get(0), args.get(1), Math::atan2); + case EXP: + return apply(args.get(0), Math::exp); + case EXPM1: + return apply(args.get(0), Math::expm1); + case SQRT: + return apply(args.get(0), Math::sqrt); + case CBRT: + return apply(args.get(0), Math::cbrt); + case GET_EXP: + return apply(args.get(0), (x) -> (double) Math.getExponent(x)); + case HYPOT: + return apply(args.get(0), args.get(1), Math::hypot); + case LOG: + return apply(args.get(0), Math::log); + case LOG10: + return apply(args.get(0), Math::log10); + case LOG1P: + return apply(args.get(0), Math::log1p); + case CEIL: + return apply(args.get(0), Math::ceil); + case FLOOR: + return apply(args.get(0), Math::floor); + case FLOOR_DIV: + return apply(args.get(0), args.get(1), (a, b) -> (double) Math.floorDiv(a.longValue(), b.longValue())); + case FLOOR_MOD: + return apply(args.get(0), args.get(1), (a, b) -> (double) Math.floorMod(a.longValue(), b.longValue())); + case ABS: + return apply(args.get(0), Math::abs); + case MIN: + return apply(args.get(0), args.get(1), Math::min); + case MAX: + return apply(args.get(0), args.get(1), Math::max); + case POW: + return apply(args.get(0), args.get(1), Math::pow); + case SIGNUM: + return apply(args.get(0), Math::signum); + case RAD: + return apply(args.get(0), Math::toRadians); + case DEG: + return apply(args.get(0), Math::toDegrees); + case CUSTOM: + var expr = customExpression.get(); + if (expr == null) { + expr = new ExpressionBuilder(config.getCustomFunction()) + .implicitMultiplication(true) + .variables(config.getArguments().stream().map(TbMathArgument::getName).collect(Collectors.toSet())) + .build(); + customExpression.set(expr); + } + for (int i = 0; i < config.getArguments().size(); i++) { + expr.setVariable(config.getArguments().get(i).getName(), args.get(i).getValue()); + } + return expr.evaluate(); + default: + throw new RuntimeException("Not supported operation: " + config.getOperation()); + } + } + + private double apply(TbMathArgumentValue arg, Function function) { + return function.apply(arg.getValue()); + } + + private double apply(TbMathArgumentValue arg1, TbMathArgumentValue arg2, BiFunction function) { + return function.apply(arg1.getValue(), arg2.getValue()); + } + + private ListenableFuture resolveArguments(TbContext ctx, TbMsg msg, Optional msgBodyOpt, TbMathArgument arg) { + switch (arg.getType()) { + case CONSTANT: + return Futures.immediateFuture(TbMathArgumentValue.constant(arg)); + case MESSAGE_BODY: + return Futures.immediateFuture(TbMathArgumentValue.fromMessageBody(arg, msgBodyOpt)); + case MESSAGE_METADATA: + return Futures.immediateFuture(TbMathArgumentValue.fromMessageMetadata(arg, msg.getMetaData())); + case ATTRIBUTE: + String scope = getAttributeScope(arg.getAttributeScope()); + return Futures.transform(ctx.getAttributesService().find(ctx.getTenantId(), msg.getOriginator(), scope, arg.getKey()), + opt -> getTbMathArgumentValue(arg, opt, "Attribute: " + arg.getKey() + " with scope: " + scope + " not found for entity: " + msg.getOriginator()) + , MoreExecutors.directExecutor()); + case TIME_SERIES: + return Futures.transform(ctx.getTimeseriesService().findLatest(ctx.getTenantId(), msg.getOriginator(), arg.getKey()), + opt -> getTbMathArgumentValue(arg, opt, "Time-series: " + arg.getKey() + " not found for entity: " + msg.getOriginator()) + , MoreExecutors.directExecutor()); + default: + throw new RuntimeException("Unsupported argument type: " + arg.getType() + "!"); + } + + } + + private String getAttributeScope(String attrScope) { + return StringUtils.isEmpty(attrScope) ? DataConstants.SERVER_SCOPE : attrScope; + } + + private TbMathArgumentValue getTbMathArgumentValue(TbMathArgument arg, Optional kvOpt, String error) { + if (kvOpt != null && kvOpt.isPresent()) { + var kv = kvOpt.get(); + switch (kv.getDataType()) { + case LONG: + return TbMathArgumentValue.fromLong(kv.getLongValue().get()); + case DOUBLE: + return TbMathArgumentValue.fromDouble(kv.getDoubleValue().get()); + default: + return TbMathArgumentValue.fromString(kv.getValueAsString()); + } + } else { + if (arg.getDefaultValue() != null) { + return TbMathArgumentValue.fromDouble(arg.getDefaultValue()); + } else { + throw new RuntimeException(error); + } + } + } + + @Override + public void destroy() { + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java new file mode 100644 index 0000000000..a51307d52a --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2022 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.math; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; + +import java.util.Arrays; +import java.util.List; + +@Data +public class TbMathNodeConfiguration implements NodeConfiguration { + + private TbRuleNodeMathFunctionType operation; + private List arguments; + private String customFunction; + private TbMathResult result; + + @Override + public TbMathNodeConfiguration defaultConfiguration() { + TbMathNodeConfiguration configuration = new TbMathNodeConfiguration(); + configuration.setOperation(TbRuleNodeMathFunctionType.ADD); + configuration.setArguments(Arrays.asList(new TbMathArgument("x", TbMathArgumentType.CONSTANT, "2"), new TbMathArgument("y", TbMathArgumentType.CONSTANT, "2"))); + configuration.setResult(new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "result", 2, false, false, null)); + return configuration; + } +} \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathResult.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathResult.java new file mode 100644 index 0000000000..833d8b794d --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathResult.java @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2022 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.math; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TbMathResult { + + private TbMathArgumentType type; + private String key; + // 0 means integer, x > 0 means x decimal points after "."; + private int resultValuePrecision; + private boolean addToBody; + private boolean addToMetadata; + private String attributeScope; + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbRuleNodeMathFunctionType.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbRuleNodeMathFunctionType.java new file mode 100644 index 0000000000..ffcd518f24 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbRuleNodeMathFunctionType.java @@ -0,0 +1,51 @@ +/** + * Copyright © 2016-2022 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.math; + +import lombok.Getter; + +public enum TbRuleNodeMathFunctionType { + + ADD(2), SUB(2), MULT(2), DIV(2), + SIN, SINH, COS, COSH, TAN, TANH, ACOS, ASIN, ATAN, ATAN2(2), + EXP, EXPM1, SQRT, CBRT, GET_EXP(1, 1, true), HYPOT(2), LOG, LOG10, LOG1P, + CEIL(1, 1, true), FLOOR(1, 1, true), FLOOR_DIV(2), FLOOR_MOD(2), + ABS, MIN(2), MAX(2), POW, SIGNUM, RAD, DEG, + + CUSTOM(0, 16, false); //Custom function based on exp4j + + @Getter + private final int minArgs; + @Getter + private final int maxArgs; + @Getter + private final boolean integerResult; + + TbRuleNodeMathFunctionType() { + this(1, 1, false); + } + + TbRuleNodeMathFunctionType(int args) { + this(args, args, false); + } + + TbRuleNodeMathFunctionType(int minArgs, int maxArgs, boolean integerResult) { + this.minArgs = minArgs; + this.maxArgs = maxArgs; + this.integerResult = integerResult; + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index 9b9974cbb9..d68b29734c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -210,9 +210,13 @@ public class TbDeviceProfileNode implements TbNode { DeviceState deviceState = deviceStates.get(deviceId); if (deviceState != null) { DeviceProfileId currentProfileId = deviceState.getProfileId(); - Device device = JacksonUtil.fromString(deviceJson, Device.class); - if (!currentProfileId.equals(device.getDeviceProfileId())) { - removeDeviceState(deviceId); + try { + Device device = JacksonUtil.fromString(deviceJson, Device.class); + if (!currentProfileId.equals(device.getDeviceProfileId())) { + removeDeviceState(deviceId); + } + } catch (IllegalArgumentException e) { + log.debug("[{}] Received device update notification with non-device msg body: [{}][{}]", ctx.getSelfId(), deviceId, e); } } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/AttributesDeleteNodeCallback.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/AttributesDeleteNodeCallback.java new file mode 100644 index 0000000000..57bfc5d129 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/AttributesDeleteNodeCallback.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2022 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.telemetry; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.server.common.msg.TbMsg; + +import javax.annotation.Nullable; +import java.util.List; + +@Slf4j +public class AttributesDeleteNodeCallback extends TelemetryNodeCallback { + + private String scope; + private List keys; + + public AttributesDeleteNodeCallback(TbContext ctx, TbMsg msg, String scope, List keys) { + super(ctx, msg); + this.scope = scope; + this.keys = keys; + } + + @Override + public void onSuccess(@Nullable Void result) { + TbContext ctx = this.getCtx(); + TbMsg tbMsg = this.getMsg(); + ctx.enqueue(ctx.attributesDeletedActionMsg(tbMsg.getOriginator(), ctx.getSelfId(), scope, keys), + () -> ctx.tellSuccess(tbMsg), + throwable -> ctx.tellFailure(tbMsg, throwable)); + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/AttributesUpdateNodeCallback.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/AttributesUpdateNodeCallback.java new file mode 100644 index 0000000000..f8ee4a29b1 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/AttributesUpdateNodeCallback.java @@ -0,0 +1,44 @@ +/** + * Copyright © 2016-2022 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.telemetry; + +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.msg.TbMsg; + +import javax.annotation.Nullable; +import java.util.List; + +public class AttributesUpdateNodeCallback extends TelemetryNodeCallback { + + private String scope; + private List attributes; + + public AttributesUpdateNodeCallback(TbContext ctx, TbMsg msg, String scope, List attributes) { + super(ctx, msg); + this.scope = scope; + this.attributes = attributes; + } + + @Override + public void onSuccess(@Nullable Void result) { + TbContext ctx = this.getCtx(); + TbMsg tbMsg = this.getMsg(); + ctx.enqueue(ctx.attributesUpdatedActionMsg(tbMsg.getOriginator(), ctx.getSelfId(), scope, attributes), + () -> ctx.tellSuccess(tbMsg), + throwable -> ctx.tellFailure(tbMsg, throwable)); + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java index 9f1c0d4e20..b810774832 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java @@ -31,7 +31,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import java.util.ArrayList; -import java.util.Set; +import java.util.List; @Slf4j @RuleNode( @@ -39,7 +39,9 @@ import java.util.Set; name = "save attributes", configClazz = TbMsgAttributesNodeConfiguration.class, nodeDescription = "Saves attributes data", - nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type", + nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type. " + + "If upsert(update/insert) operation is completed successfully, rule node will send the \"Attributes Updated\" " + + "event to the root chain of the message originator and send the incoming message via Success chain, otherwise, Failure chain is used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeAttributesConfig", icon = "file_upload" @@ -63,15 +65,19 @@ public class TbMsgAttributesNode implements TbNode { return; } String src = msg.getData(); - Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(src)); + List attributes = new ArrayList<>(JsonConverter.convertToAttributes(new JsonParser().parse(src))); + if (attributes.isEmpty()) { + ctx.tellSuccess(msg); + return; + } String notifyDeviceStr = msg.getMetaData().getValue("notifyDevice"); ctx.getTelemetryService().saveAndNotify( ctx.getTenantId(), msg.getOriginator(), config.getScope(), - new ArrayList<>(attributes), + attributes, config.getNotifyDevice() || StringUtils.isEmpty(notifyDeviceStr) || Boolean.parseBoolean(notifyDeviceStr), - new TelemetryNodeCallback(ctx, msg) + new AttributesUpdateNodeCallback(ctx, msg, config.getScope(), attributes) ); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributes.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributes.java new file mode 100644 index 0000000000..e8839291a0 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributes.java @@ -0,0 +1,73 @@ +/** + * Copyright © 2016-2022 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.telemetry; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +@Slf4j +@RuleNode( + type = ComponentType.ACTION, + name = "delete attributes", + configClazz = TbMsgDeleteAttributesConfiguration.class, + nodeDescription = "Delete attributes for Message Originator.", + nodeDetails = "Attempt to remove attributes by selected keys. If msg originator doesn't have an attribute with " + + " a key selected in the configuration, it will be ignored. If delete operation is completed successfully, " + + " rule node will send the \"Attributes Deleted\" event to the root chain of the message originator and " + + " send the incoming message via Success chain, otherwise, Failure chain is used.", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbActionNodeDeleteAttributesConfig", + icon = "remove_circle" +) +public class TbMsgDeleteAttributes implements TbNode { + + private TbMsgDeleteAttributesConfiguration config; + private String scope; + private List keys; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbMsgDeleteAttributesConfiguration.class); + this.scope = config.getScope(); + this.keys = config.getKeys(); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { + List keysToDelete = keys.stream() + .map(keyPattern -> TbNodeUtils.processPattern(keyPattern, msg)) + .distinct() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + if (keysToDelete.isEmpty()) { + ctx.tellSuccess(msg); + } else { + ctx.getTelemetryService().deleteAndNotify(ctx.getTenantId(), msg.getOriginator(), scope, keysToDelete, new AttributesDeleteNodeCallback(ctx, msg, scope, keysToDelete)); + } + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesConfiguration.java new file mode 100644 index 0000000000..03bef2a4e6 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesConfiguration.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2022 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.telemetry; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; +import org.thingsboard.server.common.data.DataConstants; + +import java.util.Collections; +import java.util.List; + +@Data +public class TbMsgDeleteAttributesConfiguration implements NodeConfiguration { + + private String scope; + private List keys; + + @Override + public TbMsgDeleteAttributesConfiguration defaultConfiguration() { + TbMsgDeleteAttributesConfiguration configuration = new TbMsgDeleteAttributesConfiguration(); + configuration.setScope(DataConstants.SERVER_SCOPE); + configuration.setKeys(Collections.emptyList()); + return configuration; + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java index 29c61b81c7..e51a2d9205 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java @@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.queue.RuleEngineException; @@ -81,7 +82,7 @@ public abstract class TbAbstractTransformNode implements TbNode { ctx.tellFailure(msg, e); } }); - msgs.forEach(newMsg -> ctx.enqueueForTellNext(newMsg, "Success", wrapper::onSuccess, wrapper::onFailure)); + msgs.forEach(newMsg -> ctx.enqueueForTellNext(newMsg, TbRelationTypes.SUCCESS, wrapper::onSuccess, wrapper::onFailure)); } } else { ctx.tellNext(msg, FAILURE); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNode.java new file mode 100644 index 0000000000..266c19fe5b --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNode.java @@ -0,0 +1,107 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.regex.Pattern; + +@Slf4j +@RuleNode( + type = ComponentType.TRANSFORMATION, + name = "copy keys", + configClazz = TbCopyKeysNodeConfiguration.class, + nodeDescription = "Copies the msg or metadata keys with specified key names selected in the list", + nodeDetails = "Will fetch fields values specified in list. If specified field is not part of msg or metadata fields it will be ignored." + + "Returns transformed messages via Success chain", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbTransformationNodeCopyKeysConfig", + icon = "content_copy" +) +public class TbCopyKeysNode implements TbNode { + + private TbCopyKeysNodeConfiguration config; + private List patternKeys; + private boolean fromMetadata; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbCopyKeysNodeConfiguration.class); + this.fromMetadata = config.isFromMetadata(); + this.patternKeys = new ArrayList<>(); + config.getKeys().forEach(key -> { + this.patternKeys.add(Pattern.compile(key)); + }); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { + TbMsgMetaData metaData = msg.getMetaData(); + String msgData = msg.getData(); + boolean msgChanged = false; + JsonNode dataNode = JacksonUtil.toJsonNode(msgData); + if (dataNode.isObject()) { + if (fromMetadata) { + ObjectNode msgDataNode = (ObjectNode) dataNode; + Map metaDataMap = metaData.getData(); + for (Map.Entry entry : metaDataMap.entrySet()) { + String keyData = entry.getKey(); + if (checkKey(keyData)) { + msgChanged = true; + msgDataNode.put(keyData, entry.getValue()); + } + } + msgData = JacksonUtil.toString(msgDataNode); + } else { + Iterator> iteratorNode = dataNode.fields(); + while (iteratorNode.hasNext()) { + Map.Entry entry = iteratorNode.next(); + String keyData = entry.getKey(); + if (checkKey(keyData)) { + msgChanged = true; + metaData.putValue(keyData, JacksonUtil.toString(entry.getValue())); + } + } + } + } + if (msgChanged) { + ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, msgData)); + } else { + ctx.tellSuccess(msg); + } + } + + boolean checkKey(String key) { + return patternKeys.stream().anyMatch(pattern -> pattern.matcher(key).matches()); + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeConfiguration.java new file mode 100644 index 0000000000..69f2a81465 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeConfiguration.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2022 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.transform; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; + +import java.util.Collections; +import java.util.Set; + +@Data +public class TbCopyKeysNodeConfiguration implements NodeConfiguration { + + private boolean fromMetadata; + private Set keys; + + @Override + public TbCopyKeysNodeConfiguration defaultConfiguration() { + TbCopyKeysNodeConfiguration configuration = new TbCopyKeysNodeConfiguration(); + configuration.setKeys(Collections.emptySet()); + configuration.setFromMetadata(false); + return configuration; + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNode.java new file mode 100644 index 0000000000..dfe3b05846 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNode.java @@ -0,0 +1,105 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.regex.Pattern; + +@Slf4j +@RuleNode( + type = ComponentType.TRANSFORMATION, + name = "delete keys", + configClazz = TbDeleteKeysNodeConfiguration.class, + nodeDescription = "Removes keys from the msg data or metadata with the specified key names selected in the list", + nodeDetails = "Will fetch fields (regex) values specified in list. If specified field (regex) is not part of msg " + + "or metadata fields it will be ignored. Returns transformed messages via Success chain", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbTransformationNodeDeleteKeysConfig", + icon = "remove_circle" +) +public class TbDeleteKeysNode implements TbNode { + + private TbDeleteKeysNodeConfiguration config; + private List patternKeys; + private boolean fromMetadata; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbDeleteKeysNodeConfiguration.class); + this.fromMetadata = config.isFromMetadata(); + this.patternKeys = new ArrayList<>(); + config.getKeys().forEach(key -> { + this.patternKeys.add(Pattern.compile(key)); + }); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { + TbMsgMetaData metaData = msg.getMetaData(); + String msgData = msg.getData(); + List keysToDelete = new ArrayList<>(); + if (fromMetadata) { + Map metaDataMap = metaData.getData(); + metaDataMap.forEach((keyMetaData, valueMetaData) -> { + if (checkKey(keyMetaData)) { + keysToDelete.add(keyMetaData); + } + }); + keysToDelete.forEach(key -> metaDataMap.remove(key)); + metaData = new TbMsgMetaData(metaDataMap); + } else { + JsonNode dataNode = JacksonUtil.toJsonNode(msgData); + if (dataNode.isObject()) { + ObjectNode msgDataObject = (ObjectNode) dataNode; + dataNode.fields().forEachRemaining(entry -> { + String keyData = entry.getKey(); + if (checkKey(keyData)) { + keysToDelete.add(keyData); + } + }); + msgDataObject.remove(keysToDelete); + msgData = JacksonUtil.toString(msgDataObject); + } + } + if (keysToDelete.isEmpty()) { + ctx.tellSuccess(msg); + } else { + ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, msgData)); + } + } + + boolean checkKey(String key) { + return patternKeys.stream().anyMatch(pattern -> pattern.matcher(key).matches()); + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeConfiguration.java new file mode 100644 index 0000000000..5666aaffca --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeConfiguration.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2022 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.transform; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; + +import java.util.Collections; +import java.util.Set; + +@Data +public class TbDeleteKeysNodeConfiguration implements NodeConfiguration { + + private boolean fromMetadata; + private Set keys; + + @Override + public TbDeleteKeysNodeConfiguration defaultConfiguration() { + TbDeleteKeysNodeConfiguration configuration = new TbDeleteKeysNodeConfiguration(); + configuration.setKeys(Collections.emptySet()); + configuration.setFromMetadata(false); + return configuration; + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java new file mode 100644 index 0000000000..ff5b8a1ece --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java @@ -0,0 +1,82 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.JsonPath; +import com.jayway.jsonpath.PathNotFoundException; +import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; + +import java.util.concurrent.ExecutionException; + +@Slf4j +@RuleNode( + type = ComponentType.TRANSFORMATION, + name = "json path", + configClazz = TbJsonPathNodeConfiguration.class, + nodeDescription = "Transforms incoming message body using JSONPath expression.", + nodeDetails = "JSONPath expression specifies a path to an element or a set of elements in a JSON structure.
" + + "'$' represents the root object or array.
" + + "If JSONPath expression evaluation failed, incoming message routes via Failure chain, " + + "otherwise Success chain is used.", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + icon = "functions", + configDirective = "tbTransformationNodeJsonPathConfig" +) +public class TbJsonPathNode implements TbNode { + + private TbJsonPathNodeConfiguration config; + private Configuration configurationJsonPath; + private JsonPath jsonPath; + private String jsonPathValue; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbJsonPathNodeConfiguration.class); + this.jsonPathValue = config.getJsonPath(); + if (!TbJsonPathNodeConfiguration.DEFAULT_JSON_PATH.equals(this.jsonPathValue)) { + this.configurationJsonPath = Configuration.builder() + .jsonProvider(new JacksonJsonNodeJsonProvider()) + .build(); + this.jsonPath = JsonPath.compile(config.getJsonPath()); + } + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { + if (!TbJsonPathNodeConfiguration.DEFAULT_JSON_PATH.equals(this.jsonPathValue)) { + try { + JsonNode jsonPathData = jsonPath.read(msg.getData(), this.configurationJsonPath); + ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(jsonPathData))); + } catch (PathNotFoundException e) { + ctx.tellFailure(msg, e); + } + } else { + ctx.tellSuccess(msg); + } + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeConfiguration.java new file mode 100644 index 0000000000..ac7ec6b2b2 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeConfiguration.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2022 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.transform; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; + +@Data +public class TbJsonPathNodeConfiguration implements NodeConfiguration { + + static final String DEFAULT_JSON_PATH = "$"; + private String jsonPath; + + @Override + public TbJsonPathNodeConfiguration defaultConfiguration() { + TbJsonPathNodeConfiguration configuration = new TbJsonPathNodeConfiguration(); + configuration.setJsonPath(DEFAULT_JSON_PATH); + return configuration; + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java new file mode 100644 index 0000000000..489e0278a3 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java @@ -0,0 +1,97 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.Map; +import java.util.concurrent.ExecutionException; + +@Slf4j +@RuleNode( + type = ComponentType.TRANSFORMATION, + name = "rename keys", + configClazz = TbRenameKeysNodeConfiguration.class, + nodeDescription = "Renames msg data or metadata keys to the new key names selected in the key mapping.", + nodeDetails = "If the key that is selected in the key mapping is missed in the selected msg source(data or metadata), it will be ignored." + + " Returns transformed messages via Success chain", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbTransformationNodeRenameKeysConfig", + icon = "find_replace" +) +public class TbRenameKeysNode implements TbNode { + + private TbRenameKeysNodeConfiguration config; + private Map renameKeysMapping; + private boolean fromMetadata; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, TbRenameKeysNodeConfiguration.class); + this.renameKeysMapping = config.getRenameKeysMapping(); + this.fromMetadata = config.isFromMetadata(); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { + TbMsgMetaData metaData = msg.getMetaData(); + String data = msg.getData(); + boolean msgChanged = false; + if (fromMetadata) { + Map metaDataMap = metaData.getData(); + for (Map.Entry entry : renameKeysMapping.entrySet()) { + String nameKey = entry.getKey(); + if (metaDataMap.containsKey(nameKey)) { + msgChanged = true; + metaDataMap.put(entry.getValue(), metaDataMap.get(nameKey)); + metaDataMap.remove(nameKey); + } + } + metaData = new TbMsgMetaData(metaDataMap); + } else { + JsonNode dataNode = JacksonUtil.toJsonNode(msg.getData()); + if (dataNode.isObject()) { + ObjectNode msgData = (ObjectNode) dataNode; + for (Map.Entry entry : renameKeysMapping.entrySet()) { + String nameKey = entry.getKey(); + if (msgData.has(nameKey)) { + msgChanged = true; + msgData.set(entry.getValue(), msgData.get(nameKey)); + msgData.remove(nameKey); + } + } + data = JacksonUtil.toString(msgData); + } + } + if (msgChanged) { + ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, data)); + } else { + ctx.tellSuccess(msg); + } + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeConfiguration.java new file mode 100644 index 0000000000..08a46899e2 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeConfiguration.java @@ -0,0 +1,37 @@ +/** + * Copyright © 2016-2022 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.transform; + +import lombok.Data; +import org.thingsboard.rule.engine.api.NodeConfiguration; + +import java.util.Map; + +@Data +public class TbRenameKeysNodeConfiguration implements NodeConfiguration { + + private boolean fromMetadata; + private Map renameKeysMapping; + + @Override + public TbRenameKeysNodeConfiguration defaultConfiguration() { + TbRenameKeysNodeConfiguration configuration = new TbRenameKeysNodeConfiguration(); + configuration.setRenameKeysMapping(Map.of("temp", "temperature")); + configuration.setFromMetadata(false); + return configuration; + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java new file mode 100644 index 0000000000..2dc27b6f92 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java @@ -0,0 +1,85 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.queue.RuleEngineException; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; + +import java.util.concurrent.ExecutionException; + +@Slf4j +@RuleNode( + type = ComponentType.EXTERNAL, + name = "split array msg", + configClazz = EmptyNodeConfiguration.class, + nodeDescription = "Split array message into several msgs", + nodeDetails = "Split the array fetched from the msg body. If the msg data is not a JSON object returns the " + + "incoming message as outbound message with Failure chain, otherwise returns " + + "inner objects of the extracted array as separate messages via Success chain.", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + icon = "content_copy", + configDirective = "tbNodeEmptyConfig" +) +public class TbSplitArrayMsgNode implements TbNode { + + private EmptyNodeConfiguration config; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { + JsonNode jsonNode = JacksonUtil.toJsonNode(msg.getData()); + if (jsonNode.isArray()) { + ArrayNode data = (ArrayNode) jsonNode; + if (data.size() == 1) { + ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(data.get(0)))); + } else { + TbMsgCallbackWrapper wrapper = new MultipleTbMsgsCallbackWrapper(data.size(), new TbMsgCallback() { + @Override + public void onSuccess() { + ctx.ack(msg); + } + + @Override + public void onFailure(RuleEngineException e) { + ctx.tellFailure(msg, e); + } + }); + data.forEach(msgNode -> ctx.enqueueForTellNext(TbMsg.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(msgNode)), + TbRelationTypes.SUCCESS, wrapper::onSuccess, wrapper::onFailure)); + } + } else { + ctx.tellFailure(msg, new RuntimeException("Msg data is not a JSON Array!")); + } + } +} diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index bf3bea8776..25ea0336c9 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1 +1 @@ -System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/material/form-field","@angular/material/checkbox","@angular/flex-layout/flex","@ngx-translate/core","@angular/material/input","@angular/common","@angular/platform-browser","@angular/material/select","@angular/material/core","@angular/material/expansion","@shared/components/button/toggle-password.component","@shared/components/file-input.component","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@angular/cdk/keycodes","@angular/material/chips","@angular/material/icon","@angular/flex-layout/extended","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","rxjs/operators","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@home/components/public-api","@shared/components/relation/relation-type-autocomplete.component","@shared/components/entity/entity-subtype-list.component","@home/components/relation/relation-filters.component","rxjs","@angular/material/autocomplete","@shared/pipe/highlight.pipe","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,o,r,a,n,l,i,s,m,u,p,d,f,c,g,x,y,b,h,C,F,L,v,I,N,T,q,k,M,S,A,G,D,V,E,P,R,w,O,H,U,K,B,j,z,_,Q,$,W,Y,J,Z,X,ee,te,oe,re,ae,ne,le,ie,se,me,ue,pe,de,fe,ce,ge,xe,ye,be,he,Ce,Fe,Le,ve,Ie;return{setters:[function(e){t=e,o=e.Component,r=e.Pipe,a=e.ViewChild,n=e.forwardRef,l=e.Input,i=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.AlarmSeverity,f=e.alarmSeverityTranslations,c=e.EntitySearchDirection,g=e.entitySearchDirectionTranslations,x=e.EntityType,y=e.PageComponent,b=e.MessageType,h=e.messageTypeNames,C=e,F=e.SharedModule,L=e.AggregationType,v=e.aggregationTranslations,I=e.alarmStatusTranslations,N=e.AlarmStatus},function(e){T=e},function(e){q=e,k=e.Validators,M=e.NgControl,S=e.NG_VALUE_ACCESSOR,A=e.NG_VALIDATORS,G=e.FormControl},function(e){D=e},function(e){V=e},function(e){E=e},function(e){P=e},function(e){R=e},function(e){w=e,O=e.CommonModule},function(e){H=e},function(e){U=e},function(e){K=e},function(e){B=e},function(e){j=e},function(e){z=e},function(e){_=e},function(e){Q=e,$=e.isDefinedAndNotNull,W=e.isNotEmptyStr},function(e){Y=e},function(e){J=e},function(e){Z=e.ENTER,X=e.COMMA,ee=e.SEMICOLON},function(e){te=e},function(e){oe=e},function(e){re=e},function(e){ae=e},function(e){ne=e},function(e){le=e.coerceBooleanProperty},function(e){ie=e},function(e){se=e},function(e){me=e.distinctUntilChanged,ue=e.startWith,pe=e.map,de=e.mergeMap,fe=e.share},function(e){ce=e},function(e){ge=e},function(e){xe=e.HomeComponentsModule},function(e){ye=e},function(e){be=e},function(e){he=e},function(e){Ce=e.of},function(e){Fe=e},function(e){Le=e},function(e){ve=e},function(e){Ie=e}],execute:function(){class Ne extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Ne),Ne.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ne,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ne.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ne,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ne,decorators:[{type:o,args:[{selector:"tb-node-empty-config",template:"
",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Te{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Te),Te.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Te,deps:[{token:H.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Te.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Te,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Te,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:H.DomSanitizer}]}});class qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[k.required,k.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[k.required,k.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",qe),qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qe,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),qe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qe,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qe,decorators:[{type:o,args:[{selector:"tb-action-node-assign-to-customer-config",templateUrl:"./assign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ke extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[k.required]],notifyDevice:[!e||e.notifyDevice,[]]})}}var Me;e("AttributesConfigComponent",ke),ke.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ke,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ke.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ke,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ke,decorators:[{type:o,args:[{selector:"tb-action-node-attributes-config",templateUrl:"./attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(Me||(Me={}));const Se=new Map([[Me.CUSTOMER,"tb.rulenode.originator-customer"],[Me.TENANT,"tb.rulenode.originator-tenant"],[Me.RELATED,"tb.rulenode.originator-related"],[Me.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);var Ae;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(Ae||(Ae={}));const Ge=new Map([[Ae.CIRCLE,"tb.rulenode.perimeter-circle"],[Ae.POLYGON,"tb.rulenode.perimeter-polygon"]]);var De;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(De||(De={}));const Ve=new Map([[De.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[De.SECONDS,"tb.rulenode.time-unit-seconds"],[De.MINUTES,"tb.rulenode.time-unit-minutes"],[De.HOURS,"tb.rulenode.time-unit-hours"],[De.DAYS,"tb.rulenode.time-unit-days"]]);var Ee;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(Ee||(Ee={}));const Pe=new Map([[Ee.METER,"tb.rulenode.range-unit-meter"],[Ee.KILOMETER,"tb.rulenode.range-unit-kilometer"],[Ee.FOOT,"tb.rulenode.range-unit-foot"],[Ee.MILE,"tb.rulenode.range-unit-mile"],[Ee.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var Re;!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(Re||(Re={}));const we=new Map([[Re.TITLE,"tb.rulenode.entity-details-title"],[Re.COUNTRY,"tb.rulenode.entity-details-country"],[Re.STATE,"tb.rulenode.entity-details-state"],[Re.CITY,"tb.rulenode.entity-details-city"],[Re.ZIP,"tb.rulenode.entity-details-zip"],[Re.ADDRESS,"tb.rulenode.entity-details-address"],[Re.ADDRESS2,"tb.rulenode.entity-details-address2"],[Re.PHONE,"tb.rulenode.entity-details-phone"],[Re.EMAIL,"tb.rulenode.entity-details-email"],[Re.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var Oe,He,Ue;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(Oe||(Oe={})),function(e){e.ASC="ASC",e.DESC="DESC"}(He||(He={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Ue||(Ue={}));const Ke=new Map([[Ue.STANDARD,"tb.rulenode.sqs-queue-standard"],[Ue.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Be=["anonymous","basic","cert.PEM"],je=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),ze=["sas","cert.PEM"],_e=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Qe;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Qe||(Qe={}));const $e=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],We=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=ze,this.azureIotHubCredentialsTypeTranslationsMap=_e}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[k.required]],host:[e?e.host:null,[k.required]],port:[e?e.port:null,[k.required,k.min(1),k.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[k.required,k.min(1),k.max(200)]],clientId:[e?e.clientId:null,[k.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[k.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),o=t.get("type").value;switch(e&&t.reset({type:o},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),o){case"sas":t.get("sasKey").setValidators([k.required]);break;case"cert.PEM":t.get("privateKey").setValidators([k.required]),t.get("privateKeyFileName").setValidators([k.required]),t.get("cert").setValidators([k.required]),t.get("certFileName").setValidators([k.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ye,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ye,selector:"tb-action-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}:host mat-checkbox{padding-bottom:16px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:z.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:B.MatAccordion,selector:"mat-accordion",inputs:["multi","displayMode","togglePosition","hideToggle"],exportAs:["matAccordion"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:q.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:w.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ye,decorators:[{type:o,args:[{selector:"tb-action-node-azure-iot-hub-config",templateUrl:"./azure-iot-hub-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Je extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[k.required]]})}}e("CheckPointConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Je,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Je,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',components:[{type:_.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","required","queueType","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Je,decorators:[{type:o,args:[{selector:"tb-action-node-check-point-config",templateUrl:"./check-point-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ze extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[k.required]],alarmType:[e?e.alarmType:null,[k.required]]})}testScript(){const e=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((e=>{e&&this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ze,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ze,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ze,decorators:[{type:o,args:[{selector:"tb-action-node-clear-alarm-config",templateUrl:"./clear-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Xe extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r,this.alarmSeverities=Object.keys(d),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[k.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData"]}updateValidators(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([k.required]),this.createAlarmConfigForm.get("severity").setValidators([k.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})}testScript(){const e=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((e=>{e&&this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}removeKey(e,t){const o=this.createAlarmConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.createAlarmConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;e&&!t||this.jsFuncComponent.validateOnSubmit()}}e("CreateAlarmConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xe,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Xe,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:re.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xe,decorators:[{type:o,args:[{selector:"tb-action-node-create-alarm-config",templateUrl:"./create-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[k.required]],entityType:[e?e.entityType:null,[k.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[k.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[k.required,k.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([k.required,k.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([k.required,k.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:et,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:et,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:et,decorators:[{type:o,args:[{selector:"tb-action-node-create-relation-config",templateUrl:"./create-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[k.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[k.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[k.required,k.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,o=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([k.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&o?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([k.required,k.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:tt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:tt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:tt,decorators:[{type:o,args:[{selector:"tb-action-node-delete-relation-config",templateUrl:"./delete-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,k.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,k.required]})}}e("DeviceProfileConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ot,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ot,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ot,decorators:[{type:o,args:[{selector:"tb-device-profile-config",templateUrl:"./device-profile-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class rt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[k.required,k.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[k.required,k.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[k.required]]})}prepareInputConfig(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((e=>{e&&this.generatorConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("GeneratorConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:rt,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:rt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:ne.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:rt,decorators:[{type:o,args:[{selector:"tb-action-node-generator-config",templateUrl:"./generator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class at extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Ae,this.perimeterTypes=Object.keys(Ae),this.perimeterTypeTranslationMap=Ge,this.rangeUnits=Object.keys(Ee),this.rangeUnitTranslationMap=Pe,this.timeUnits=Object.keys(De),this.timeUnitsTranslationMap=Ve}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[k.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[k.required]],perimeterType:[e?e.perimeterType:null,[k.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[k.required,k.min(1),k.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[k.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[k.required,k.min(1),k.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[k.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([k.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||o!==Ae.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([k.required,k.min(-90),k.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([k.required,k.min(-180),k.max(180)]),this.geoActionConfigForm.get("range").setValidators([k.required,k.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([k.required])),t||o!==Ae.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([k.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",at),at.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:at,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),at.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:at,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:at,decorators:[{type:o,args:[{selector:"tb-action-node-gps-geofencing-config",templateUrl:"./gps-geo-action-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class nt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.injector=o,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.ngControl=this.injector.get(M),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const o of Object.keys(e))Object.prototype.hasOwnProperty.call(e,o)&&t.push(this.fb.group({key:[o,[k.required]],value:[e[o],[k.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[k.required]],value:["",[k.required]]}))}validate(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:nt,deps:[{token:T.Store},{token:P.TranslateService},{token:t.Injector},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:nt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:S,useExisting:n((()=>nt)),multi:!0},{provide:A,useExisting:n((()=>nt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0;align-self:baseline}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:re.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{type:q.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:se.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:nt,decorators:[{type:o,args:[{selector:"tb-kv-map-config",templateUrl:"./kv-map-config.component.html",styleUrls:["./kv-map-config.component.scss"],providers:[{provide:S,useExisting:n((()=>nt)),multi:!0},{provide:A,useExisting:n((()=>nt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:t.Injector},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:l}],requiredText:[{type:l}],keyText:[{type:l}],keyRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],required:[{type:l}]}});class lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=$e,this.ToByteStandartCharsetTypeTranslationMap=We}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[k.required]],bootstrapServers:[e?e.bootstrapServers:null,[k.required]],retries:[e?e.retries:null,[k.min(0)]],batchSize:[e?e.batchSize:null,[k.min(0)]],linger:[e?e.linger:null,[k.min(0)]],bufferMemory:[e?e.bufferMemory:null,[k.min(0)]],acks:[e?e.acks:null,[k.required]],keySerializer:[e?e.keySerializer:null,[k.required]],valueSerializer:[e?e.valueSerializer:null,[k.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([k.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",lt),lt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:lt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),lt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:lt,selector:"tb-action-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:lt,decorators:[{type:o,args:[{selector:"tb-action-node-kafka-config",templateUrl:"./kafka-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class it extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((e=>{e&&this.logConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",it),it.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:it,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),it.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:it,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:it,decorators:[{type:o,args:[{selector:"tb-action-node-log-config",templateUrl:"./log-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class st extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Be,this.credentialsTypeTranslationsMap=je,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[k.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(me()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const o=e[t];if(!o.firstChange&&o.currentValue!==o.previousValue&&o.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){$(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([k.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[k.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(k.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return o=>{t||(t=[Object.keys(o.controls)]);return(null==o?void 0:o.controls)&&t.some((t=>t.every((t=>!e(o.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",st),st.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:st,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),st.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:st,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:S,useExisting:n((()=>st)),multi:!0},{provide:A,useExisting:n((()=>st)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',components:[{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:z.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:B.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{type:D.MatLabel,selector:"mat-label"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:w.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:w.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:st,decorators:[{type:o,args:[{selector:"tb-credentials-config",templateUrl:"./credentials-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>st)),multi:!0},{provide:A,useExisting:n((()=>st)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]},propDecorators:{required:[{type:l}],disableCertPemCredentials:[{type:l}],passwordFieldRquired:[{type:l}]}});class mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[k.required]],host:[e?e.host:null,[k.required]],port:[e?e.port:null,[k.required,k.min(1),k.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[k.required,k.min(1),k.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&W(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{W(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",mt),mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:mt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:mt,selector:"tb-action-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}:host mat-checkbox{padding-bottom:16px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:st,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:mt,decorators:[{type:o,args:[{selector:"tb-action-node-mqtt-config",templateUrl:"./mqtt-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[k.required,k.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[k.required]]})}}e("MsgCountConfigComponent",ut),ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ut,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ut,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ut,decorators:[{type:o,args:[{selector:"tb-action-node-msg-count-config",templateUrl:"./msg-count-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[k.required,k.min(1),k.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([k.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([k.required,k.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",pt),pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:pt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:pt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:pt,decorators:[{type:o,args:[{selector:"tb-action-node-msg-delay-config",templateUrl:"./msg-delay-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[k.required]],topicName:[e?e.topicName:null,[k.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[k.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[k.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",dt),dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:dt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:dt,selector:"tb-action-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:z.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:dt,decorators:[{type:o,args:[{selector:"tb-action-node-pub-sub-config",templateUrl:"./pubsub-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[k.required]]})}}e("PushToCloudConfigComponent",ft),ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ft,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ft,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ft,decorators:[{type:o,args:[{selector:"tb-action-node-push-to-cloud-config",templateUrl:"./push-to-cloud-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[k.required]]})}}e("PushToEdgeConfigComponent",ct),ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ct,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ct,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ct,decorators:[{type:o,args:[{selector:"tb-action-node-push-to-edge-config",templateUrl:"./push-to-edge-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[k.required]],port:[e?e.port:null,[k.required,k.min(1),k.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[k.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[k.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",gt),gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:gt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:gt,selector:"tb-action-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:gt,decorators:[{type:o,args:[{selector:"tb-action-node-rabbit-mq-config",templateUrl:"./rabbit-mq-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Qe)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[k.required]],requestMethod:[e?e.requestMethod:null,[k.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[k.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,o=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[k.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[k.required,k.min(1),k.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([k.min(0)])),o?this.restApiCallConfigForm.get("maxQueueSize").setValidators([k.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",xt),xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:xt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:xt,selector:"tb-action-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{type:st,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:xt,decorators:[{type:o,args:[{selector:"tb-action-node-rest-api-call-config",templateUrl:"./rest-api-call-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",yt),yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:yt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:yt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:yt,decorators:[{type:o,args:[{selector:"tb-action-node-rpc-reply-config",templateUrl:"./rpc-reply-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[k.required,k.min(0)]]})}}e("RpcRequestConfigComponent",bt),bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:bt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:bt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:bt,decorators:[{type:o,args:[{selector:"tb-action-node-rpc-request-config",templateUrl:"./rpc-request-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[k.required,k.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[k.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",ht),ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ht,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ht,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ht,decorators:[{type:o,args:[{selector:"tb-action-node-custom-table-config",templateUrl:"./save-to-custom-table-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,o=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([k.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([k.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([k.required,k.min(1),k.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([k.required,k.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(o?[k.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(o?[k.required,k.min(1),k.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Ct),Ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ct,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ct,selector:"tb-action-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ce.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ct,decorators:[{type:o,args:[{selector:"tb-action-node-send-email-config",templateUrl:"./send-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[k.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[k.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([k.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Ft),Ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ft,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ft,selector:"tb-action-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:ge.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ft,decorators:[{type:o,args:[{selector:"tb-action-node-send-sms-config",templateUrl:"./send-sms-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[k.required]],accessKeyId:[e?e.accessKeyId:null,[k.required]],secretAccessKey:[e?e.secretAccessKey:null,[k.required]],region:[e?e.region:null,[k.required]]})}}e("SnsConfigComponent",Lt),Lt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Lt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Lt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Lt,selector:"tb-action-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Lt,decorators:[{type:o,args:[{selector:"tb-action-node-sns-config",templateUrl:"./sns-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Ue,this.sqsQueueTypes=Object.keys(Ue),this.sqsQueueTypeTranslationsMap=Ke}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[k.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[k.required]],delaySeconds:[e?e.delaySeconds:null,[k.min(0),k.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[k.required]],secretAccessKey:[e?e.secretAccessKey:null,[k.required]],region:[e?e.region:null,[k.required]]})}}e("SqsConfigComponent",vt),vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:vt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:vt,selector:"tb-action-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:vt,decorators:[{type:o,args:[{selector:"tb-action-node-sqs-config",templateUrl:"./sqs-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class It extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[k.required,k.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",It),It.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:It,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),It.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:It,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:It,decorators:[{type:o,args:[{selector:"tb-action-node-timeseries-config",templateUrl:"./timeseries-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[k.required,k.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[k.required,k.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Nt),Nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Nt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Nt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Nt,decorators:[{type:o,args:[{selector:"tb-action-node-un-assign-to-customer-config",templateUrl:"./unassign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Tt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[k.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[k.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",Tt),Tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Tt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Tt,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:S,useExisting:n((()=>Tt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ye.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]},{type:be.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Tt,decorators:[{type:o,args:[{selector:"tb-device-relations-query-config",templateUrl:"./device-relations-query-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>Tt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class qt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[k.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",qt),qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:S,useExisting:n((()=>qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:he.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qt,decorators:[{type:o,args:[{selector:"tb-relations-query-config",templateUrl:"./relations-query-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>qt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class kt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.truncate=o,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[Z,X,ee],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(b))this.messageTypesList.push({name:h.get(b[e]),value:e})}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(ue(""),pe((e=>e||"")),de((e=>this.fetchMessageTypes(e))),fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ce(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ce(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const o=e.trim(),r=this.messageTypesList.find((e=>e.name===o));t=r?{name:r.name,value:r.value}:{name:o,value:o},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",kt),kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:kt,deps:[{token:T.Store},{token:P.TranslateService},{token:C.TruncatePipe},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:kt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:S,useExisting:n((()=>kt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:Fe.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:Fe.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:Fe.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,highlight:Le.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:kt,decorators:[{type:o,args:[{selector:"tb-message-types-config",templateUrl:"./message-types-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>kt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:C.TruncatePipe},{type:q.FormBuilder}]},propDecorators:{required:[{type:l}],label:[{type:l}],placeholder:[{type:l}],disabled:[{type:l}],chipList:[{type:a,args:["chipList",{static:!1}]}],matAutocomplete:[{type:a,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:a,args:["messageTypeInput",{static:!1}]}]}});class Mt{}e("RulenodeCoreConfigCommonModule",Mt),Mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Mt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,declarations:[nt,Tt,qt,kt,st,Te],imports:[O,F,xe],exports:[nt,Tt,qt,kt,st,Te]}),Mt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,imports:[[O,F,xe]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,decorators:[{type:i,args:[{declarations:[nt,Tt,qt,kt,st,Te],imports:[O,F,xe],exports:[nt,Tt,qt,kt,st,Te]}]}]});class St{}e("RuleNodeCoreConfigActionModule",St),St.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,deps:[],target:t.ɵɵFactoryTarget.NgModule}),St.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,declarations:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft],imports:[O,F,xe,Mt],exports:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft]}),St.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,imports:[[O,F,xe,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,decorators:[{type:i,args:[{declarations:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft],imports:[O,F,xe,Mt],exports:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft]}]}]});class At extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[k.required]],outputValueKey:[e?e.outputValueKey:null,[k.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[k.min(0),k.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([k.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",At),At.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:At,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),At.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:At,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:At,decorators:[{type:o,args:[{selector:"tb-enrichment-node-calculate-delta-config",templateUrl:"./calculate-delta-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[k.required]]})}}e("CustomerAttributesConfigComponent",Gt),Gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Gt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Gt,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Gt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-customer-attributes-config",templateUrl:"./customer-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[k.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.deviceAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.deviceAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("DeviceAttributesConfigComponent",Dt),Dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Dt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Dt,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:Tt,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Dt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-device-attributes-config",templateUrl:"./device-attributes-config.component.html",styleUrls:["./device-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Vt extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.entityDetailsTranslationsMap=we,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(Re))this.entityDetailsList.push(Re[e]);this.detailsFormControl=new G(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(ue(""),pe((e=>e||"")),de((e=>this.fetchEntityDetails(e))),fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[k.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})}displayDetails(e){return e?this.translate.instant(we.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ce(this.entityDetailsList.filter((t=>this.translate.instant(we.get(Re[t])).toUpperCase().includes(e))))}return Ce(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.entityDetailsConfigForm.get("detailsList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}}addDetailsField(e){let t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Vt),Vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Vt,deps:[{token:T.Store},{token:P.TranslateService},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Vt,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:Fe.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:Fe.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:Fe.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,highlight:Le.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Vt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-entity-details-config",templateUrl:"./entity-details-config.component.html",styleUrls:["./entity-details-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:q.FormBuilder}]},propDecorators:{detailsInput:[{type:a,args:["detailsInput",{static:!1}]}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee],this.aggregationTypes=L,this.aggregations=Object.keys(L),this.aggregationTypesTranslations=v,this.fetchMode=Oe,this.fetchModes=Object.keys(Oe),this.samplingOrders=Object.keys(He),this.timeUnits=Object.values(De),this.timeUnitsTranslationMap=Ve}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[k.required]],fetchMode:[e?e.fetchMode:null,[k.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,o=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===Oe.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([k.required,k.min(2),k.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),o?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([k.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([k.required,k.min(1),k.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([k.required,k.min(1),k.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const o=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Et),Et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Et,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Et,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Et,decorators:[{type:o,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",templateUrl:"./get-telemetry-from-database-config.component.html",styleUrls:["./get-telemetry-from-database-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.originatorAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.originatorAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("OriginatorAttributesConfigComponent",Pt),Pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Pt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Pt,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Pt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-originator-attributes-config",templateUrl:"./originator-attributes-config.component.html",styleUrls:["./originator-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[k.required]]})}}e("OriginatorFieldsConfigComponent",Rt),Rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Rt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Rt,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',components:[{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Rt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-originator-fields-config",templateUrl:"./originator-fields-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class wt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[k.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[k.required]]})}}e("RelatedAttributesConfigComponent",wt),wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:wt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:wt,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:qt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:wt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-related-attributes-config",templateUrl:"./related-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[k.required]]})}}e("TenantAttributesConfigComponent",Ot),Ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ot,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ot,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ot,decorators:[{type:o,args:[{selector:"tb-enrichment-node-tenant-attributes-config",templateUrl:"./tenant-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ht{}e("RulenodeCoreConfigEnrichmentModule",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Ht.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,declarations:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At],imports:[O,F,Mt],exports:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At]}),Ht.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,decorators:[{type:i,args:[{declarations:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At],imports:[O,F,Mt],exports:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At]}]}]});class Ut extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.alarmStatusTranslationsMap=I,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(N))this.alarmStatusList.push(N[e]);this.statusFormControl=new G(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(ue(""),pe((e=>e||"")),de((e=>this.fetchAlarmStatus(e))),fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[k.required]]})}displayStatus(e){return e?this.translate.instant(I.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ce(t.filter((t=>this.translate.instant(I.get(N[t])).toUpperCase().includes(e))))}return Ce(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ut,deps:[{token:T.Store},{token:P.TranslateService},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ut,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:Fe.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:Fe.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:Fe.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,highlight:Le.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ut,decorators:[{type:o,args:[{selector:"tb-filter-node-check-alarm-status-config",templateUrl:"./check-alarm-status.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:q.FormBuilder}]},propDecorators:{alarmStatusInput:[{type:a,args:["alarmStatusInput",{static:!1}]}]}});class Kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Kt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Kt,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Kt,decorators:[{type:o,args:[{selector:"tb-filter-node-check-message-config",templateUrl:"./check-message-config.component.html",styleUrls:["./check-message-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(c),this.entitySearchDirectionTranslationsMap=g}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[k.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[k.required]:[]],relationType:[e?e.relationType:null,[k.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[k.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[k.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Bt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Bt,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{type:ve.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]},{type:ye.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Bt,decorators:[{type:o,args:[{selector:"tb-filter-node-check-relation-config",templateUrl:"./check-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Ae,this.perimeterTypes=Object.keys(Ae),this.perimeterTypeTranslationMap=Ge,this.rangeUnits=Object.keys(Ee),this.rangeUnitTranslationMap=Pe}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[k.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[k.required]],perimeterType:[e?e.perimeterType:null,[k.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([k.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||o!==Ae.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([k.required,k.min(-90),k.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([k.required,k.min(-180),k.max(180)]),this.geoFilterConfigForm.get("range").setValidators([k.required,k.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([k.required])),t||o!==Ae.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([k.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:jt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:jt,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:jt,decorators:[{type:o,args:[{selector:"tb-filter-node-gps-geofencing-config",templateUrl:"./gps-geo-filter-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[k.required]]})}}e("MessageTypeConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:zt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:zt,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',components:[{type:kt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:zt,decorators:[{type:o,args:[{selector:"tb-filter-node-message-type-config",templateUrl:"./message-type-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[k.required]]})}}e("OriginatorTypeConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:_t,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:_t,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"],components:[{type:Ie.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","allowedEntityTypes","ignoreAuthorityFilter"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:_t,decorators:[{type:o,args:[{selector:"tb-filter-node-originator-type-config",templateUrl:"./originator-type-config.component.html",styleUrls:["./originator-type-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Qt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Qt,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Qt,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Qt,decorators:[{type:o,args:[{selector:"tb-filter-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class $t extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((e=>{e&&this.switchConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:$t,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:$t,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:$t,decorators:[{type:o,args:[{selector:"tb-filter-node-switch-config",templateUrl:"./switch-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Wt{}e("RuleNodeCoreConfigFilterModule",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Wt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,declarations:[Kt,Bt,jt,zt,_t,Qt,$t,Ut],imports:[O,F,Mt],exports:[Kt,Bt,jt,zt,_t,Qt,$t,Ut]}),Wt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,decorators:[{type:i,args:[{declarations:[Kt,Bt,jt,zt,_t,Qt,$t,Ut],imports:[O,F,Mt],exports:[Kt,Bt,jt,zt,_t,Qt,$t,Ut]}]}]});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=Me,this.originatorSources=Object.keys(Me),this.originatorSourceTranslationMap=Se}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[k.required]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===Me.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([k.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Yt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Yt,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:qt,selector:"tb-relations-query-config",inputs:["disabled","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Yt,decorators:[{type:o,args:[{selector:"tb-transformation-node-change-originator-config",templateUrl:"./change-originator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Jt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Jt,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Jt,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Jt,decorators:[{type:o,args:[{selector:"tb-transformation-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[k.required]],toTemplate:[e?e.toTemplate:null,[k.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[k.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[k.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(ue([null==e?void 0:e.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(k.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Zt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Zt,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Zt,decorators:[{type:o,args:[{selector:"tb-transformation-node-to-email-config",templateUrl:"./to-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Xt{}e("RulenodeCoreConfigTransformModule",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Xt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,declarations:[Yt,Jt,Zt],imports:[O,F,Mt],exports:[Yt,Jt,Zt]}),Xt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,decorators:[{type:i,args:[{declarations:[Yt,Jt,Zt],imports:[O,F,Mt],exports:[Yt,Jt,Zt]}]}]});class eo extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[k.required]]})}}e("RuleChainInputComponent",eo),eo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:eo,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),eo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:eo,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',components:[{type:ve.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:eo,decorators:[{type:o,args:[{selector:"tb-flow-node-rule-chain-input-config",templateUrl:"./rule-chain-input.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class to extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",to),to.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:to,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),to.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:to,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:to,decorators:[{type:o,args:[{selector:"tb-flow-node-rule-chain-output-config",templateUrl:"./rule-chain-output.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class oo{}e("RuleNodeCoreConfigFlowModule",oo),oo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,deps:[],target:t.ɵɵFactoryTarget.NgModule}),oo.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,declarations:[eo,to],imports:[O,F,Mt],exports:[eo,to]}),oo.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,decorators:[{type:i,args:[{declarations:[eo,to],imports:[O,F,Mt],exports:[eo,to]}]}]});class ro{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body to substitute "Source" and "Target" key names'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",ro),ro.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,deps:[{token:P.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),ro.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,declarations:[Ne],imports:[O,F],exports:[St,Wt,Ht,Xt,oo,Ne]}),ro.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,imports:[[O,F],St,Wt,Ht,Xt,oo]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,decorators:[{type:i,args:[{declarations:[Ne],imports:[O,F],exports:[St,Wt,Ht,Xt,oo,Ne]}]}],ctorParameters:function(){return[{type:P.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/material/form-field","@angular/material/checkbox","@angular/flex-layout/flex","@ngx-translate/core","@angular/material/input","@angular/common","@angular/platform-browser","@angular/material/select","@angular/material/core","@angular/material/expansion","@shared/components/button/toggle-password.component","@shared/components/file-input.component","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@angular/cdk/keycodes","@angular/material/chips","@angular/material/icon","@angular/flex-layout/extended","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","rxjs/operators","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/autocomplete","@shared/pipe/highlight.pipe","@angular/material/list","@angular/cdk/drag-drop","@home/components/public-api","@shared/components/relation/relation-type-autocomplete.component","@shared/components/entity/entity-subtype-list.component","@home/components/relation/relation-filters.component","rxjs","@angular/material/slide-toggle","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,o,r,a,n,l,i,s,m,u,p,d,f,c,g,x,y,b,h,C,F,L,v,I,N,T,k,M,q,S,A,G,D,E,V,P,R,O,w,H,U,B,K,j,_,z,Q,$,Y,W,J,X,Z,ee,te,oe,re,ae,ne,le,ie,se,me,ue,pe,de,fe,ce,ge,xe,ye,be,he,Ce,Fe,Le,ve,Ie,Ne,Te,ke,Me;return{setters:[function(e){t=e,o=e.Component,r=e.Pipe,a=e.ViewChild,n=e.forwardRef,l=e.Input,i=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.AlarmSeverity,f=e.alarmSeverityTranslations,c=e.EntitySearchDirection,g=e.entitySearchDirectionTranslations,x=e.EntityType,y=e.PageComponent,b=e.MessageType,h=e.messageTypeNames,C=e,F=e.SharedModule,L=e.AggregationType,v=e.aggregationTranslations,I=e.alarmStatusTranslations,N=e.AlarmStatus},function(e){T=e},function(e){k=e,M=e.Validators,q=e.NgControl,S=e.NG_VALUE_ACCESSOR,A=e.NG_VALIDATORS,G=e.FormControl},function(e){D=e},function(e){E=e},function(e){V=e},function(e){P=e},function(e){R=e},function(e){O=e,w=e.CommonModule},function(e){H=e},function(e){U=e},function(e){B=e},function(e){K=e},function(e){j=e},function(e){_=e},function(e){z=e},function(e){Q=e,$=e.isDefinedAndNotNull,Y=e.isNotEmptyStr},function(e){W=e},function(e){J=e},function(e){X=e.ENTER,Z=e.COMMA,ee=e.SEMICOLON},function(e){te=e},function(e){oe=e},function(e){re=e},function(e){ae=e},function(e){ne=e},function(e){le=e.coerceBooleanProperty},function(e){ie=e},function(e){se=e},function(e){me=e.distinctUntilChanged,ue=e.tap,pe=e.map,de=e.startWith,fe=e.mergeMap,ce=e.share},function(e){ge=e},function(e){xe=e},function(e){ye=e},function(e){be=e},function(e){he=e},function(e){Ce=e},function(e){Fe=e.HomeComponentsModule},function(e){Le=e},function(e){ve=e},function(e){Ie=e},function(e){Ne=e.of},function(e){Te=e},function(e){ke=e},function(e){Me=e}],execute:function(){class qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",qe),qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:qe,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),qe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:qe,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:qe,decorators:[{type:o,args:[{selector:"tb-node-empty-config",template:"
",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Se{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Se),Se.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Se,deps:[{token:H.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Se.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Se,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Se,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:H.DomSanitizer}]}});class Ae extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[M.required,M.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[M.required,M.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",Ae),Ae.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ae,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ae.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Ae,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ae,decorators:[{type:o,args:[{selector:"tb-action-node-assign-to-customer-config",templateUrl:"./assign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Ge extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[M.required]],notifyDevice:[!e||e.notifyDevice,[]]})}}var De;e("AttributesConfigComponent",Ge),Ge.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ge,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ge.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Ge,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ge,decorators:[{type:o,args:[{selector:"tb-action-node-attributes-config",templateUrl:"./attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(De||(De={}));const Ee=new Map([[De.CUSTOMER,"tb.rulenode.originator-customer"],[De.TENANT,"tb.rulenode.originator-tenant"],[De.RELATED,"tb.rulenode.originator-related"],[De.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[De.ENTITY,"tb.rulenode.originator-entity"]]);var Ve;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(Ve||(Ve={}));const Pe=new Map([[Ve.CIRCLE,"tb.rulenode.perimeter-circle"],[Ve.POLYGON,"tb.rulenode.perimeter-polygon"]]);var Re;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(Re||(Re={}));const Oe=new Map([[Re.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[Re.SECONDS,"tb.rulenode.time-unit-seconds"],[Re.MINUTES,"tb.rulenode.time-unit-minutes"],[Re.HOURS,"tb.rulenode.time-unit-hours"],[Re.DAYS,"tb.rulenode.time-unit-days"]]);var we;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(we||(we={}));const He=new Map([[we.METER,"tb.rulenode.range-unit-meter"],[we.KILOMETER,"tb.rulenode.range-unit-kilometer"],[we.FOOT,"tb.rulenode.range-unit-foot"],[we.MILE,"tb.rulenode.range-unit-mile"],[we.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var Ue;!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(Ue||(Ue={}));const Be=new Map([[Ue.TITLE,"tb.rulenode.entity-details-title"],[Ue.COUNTRY,"tb.rulenode.entity-details-country"],[Ue.STATE,"tb.rulenode.entity-details-state"],[Ue.CITY,"tb.rulenode.entity-details-city"],[Ue.ZIP,"tb.rulenode.entity-details-zip"],[Ue.ADDRESS,"tb.rulenode.entity-details-address"],[Ue.ADDRESS2,"tb.rulenode.entity-details-address2"],[Ue.PHONE,"tb.rulenode.entity-details-phone"],[Ue.EMAIL,"tb.rulenode.entity-details-email"],[Ue.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var Ke,je,_e;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(Ke||(Ke={})),function(e){e.ASC="ASC",e.DESC="DESC"}(je||(je={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(_e||(_e={}));const ze=new Map([[_e.STANDARD,"tb.rulenode.sqs-queue-standard"],[_e.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Qe=["anonymous","basic","cert.PEM"],$e=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Ye=["sas","cert.PEM"],We=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Je;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Je||(Je={}));const Xe=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Ze=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var et;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(et||(et={}));const tt=new Map([[et.CUSTOM,{value:et.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[et.ADD,{value:et.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[et.SUB,{value:et.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[et.MULT,{value:et.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[et.DIV,{value:et.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[et.SIN,{value:et.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[et.SINH,{value:et.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[et.COS,{value:et.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[et.COSH,{value:et.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[et.TAN,{value:et.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[et.TANH,{value:et.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[et.ACOS,{value:et.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[et.ASIN,{value:et.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[et.ATAN,{value:et.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[et.ATAN2,{value:et.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[et.EXP,{value:et.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[et.EXPM1,{value:et.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[et.SQRT,{value:et.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[et.CBRT,{value:et.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[et.GET_EXP,{value:et.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[et.HYPOT,{value:et.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[et.LOG,{value:et.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[et.LOG10,{value:et.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[et.LOG1P,{value:et.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[et.CEIL,{value:et.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[et.FLOOR,{value:et.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[et.FLOOR_DIV,{value:et.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[et.FLOOR_MOD,{value:et.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[et.ABS,{value:et.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[et.MIN,{value:et.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[et.MAX,{value:et.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[et.POW,{value:et.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[et.SIGNUM,{value:et.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[et.RAD,{value:et.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[et.DEG,{value:et.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var ot,rt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(ot||(ot={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(rt||(rt={}));const at=new Map([[ot.ATTRIBUTE,"tb.rulenode.attribute-type"],[ot.TIME_SERIES,"tb.rulenode.time-series-type"],[ot.CONSTANT,"tb.rulenode.constant-type"],[ot.MESSAGE_BODY,"tb.rulenode.message-body-type"],[ot.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),nt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var lt,it;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(lt||(lt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(it||(it={}));const st=new Map([[lt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[lt.SERVER_SCOPE,"tb.rulenode.server-scope"],[lt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Ye,this.azureIotHubCredentialsTypeTranslationsMap=We}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[M.required]],host:[e?e.host:null,[M.required]],port:[e?e.port:null,[M.required,M.min(1),M.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[M.required,M.min(1),M.max(200)]],clientId:[e?e.clientId:null,[M.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[M.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),o=t.get("type").value;switch(e&&t.reset({type:o},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),o){case"sas":t.get("sasKey").setValidators([M.required]);break;case"cert.PEM":t.get("privateKey").setValidators([M.required]),t.get("privateKeyFileName").setValidators([M.required]),t.get("cert").setValidators([M.required]),t.get("certFileName").setValidators([M.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",mt),mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:mt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:mt,selector:"tb-action-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}:host mat-checkbox{padding-bottom:16px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:K.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:K.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:_.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:K.MatAccordion,selector:"mat-accordion",inputs:["multi","displayMode","togglePosition","hideToggle"],exportAs:["matAccordion"]},{type:K.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:K.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:k.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:mt,decorators:[{type:o,args:[{selector:"tb-action-node-azure-iot-hub-config",templateUrl:"./azure-iot-hub-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[M.required]]})}}e("CheckPointConfigComponent",ut),ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ut,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:ut,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',components:[{type:z.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","required","queueType","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ut,decorators:[{type:o,args:[{selector:"tb-action-node-check-point-config",templateUrl:"./check-point-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class pt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[M.required]],alarmType:[e?e.alarmType:null,[M.required]]})}testScript(){const e=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((e=>{e&&this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",pt),pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:pt,deps:[{token:T.Store},{token:k.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:pt,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',components:[{type:W.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:pt,decorators:[{type:o,args:[{selector:"tb-action-node-clear-alarm-config",templateUrl:"./clear-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class dt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r,this.alarmSeverities=Object.keys(d),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[X,Z,ee]}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[M.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData"]}updateValidators(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([M.required]),this.createAlarmConfigForm.get("severity").setValidators([M.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})}testScript(){const e=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((e=>{e&&this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}removeKey(e,t){const o=this.createAlarmConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.createAlarmConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;e&&!t||this.jsFuncComponent.validateOnSubmit()}}e("CreateAlarmConfigComponent",dt),dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:dt,deps:[{token:T.Store},{token:k.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:dt,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:W.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:re.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:dt,decorators:[{type:o,args:[{selector:"tb-action-node-create-alarm-config",templateUrl:"./create-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[M.required]],entityType:[e?e.entityType:null,[M.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[M.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[M.required,M.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([M.required,M.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([M.required,M.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",ft),ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ft,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:ft,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ft,decorators:[{type:o,args:[{selector:"tb-action-node-create-relation-config",templateUrl:"./create-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[M.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[M.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[M.required,M.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,o=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([M.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&o?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([M.required,M.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",ct),ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ct,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:ct,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ct,decorators:[{type:o,args:[{selector:"tb-action-node-delete-relation-config",templateUrl:"./delete-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,M.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,M.required]})}}e("DeviceProfileConfigComponent",gt),gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:gt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:gt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:gt,decorators:[{type:o,args:[{selector:"tb-device-profile-config",templateUrl:"./device-profile-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class xt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[M.required,M.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[M.required,M.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[M.required]]})}prepareInputConfig(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((e=>{e&&this.generatorConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("GeneratorConfigComponent",xt),xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:xt,deps:[{token:T.Store},{token:k.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:xt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:ne.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{type:W.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:xt,decorators:[{type:o,args:[{selector:"tb-action-node-generator-config",templateUrl:"./generator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Ve,this.perimeterTypes=Object.keys(Ve),this.perimeterTypeTranslationMap=Pe,this.rangeUnits=Object.keys(we),this.rangeUnitTranslationMap=He,this.timeUnits=Object.keys(Re),this.timeUnitsTranslationMap=Oe}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[M.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[M.required]],perimeterType:[e?e.perimeterType:null,[M.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[M.required,M.min(1),M.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[M.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[M.required,M.min(1),M.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[M.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([M.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||o!==Ve.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([M.required,M.min(-90),M.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([M.required,M.min(-180),M.max(180)]),this.geoActionConfigForm.get("range").setValidators([M.required,M.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([M.required])),t||o!==Ve.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([M.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",yt),yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:yt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:yt,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:yt,decorators:[{type:o,args:[{selector:"tb-action-node-gps-geofencing-config",templateUrl:"./gps-geo-action-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class bt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.injector=o,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.ngControl=this.injector.get(q),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const o of Object.keys(e))Object.prototype.hasOwnProperty.call(e,o)&&t.push(this.fb.group({key:[o,[M.required]],value:[e[o],[M.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[M.required]],value:["",[M.required]]}))}validate(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",bt),bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:bt,deps:[{token:T.Store},{token:P.TranslateService},{token:t.Injector},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:bt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:S,useExisting:n((()=>bt)),multi:!0},{provide:A,useExisting:n((()=>bt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0;align-self:baseline}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:re.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{type:k.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:se.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]}],pipes:{translate:P.TranslatePipe,async:O.AsyncPipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:bt,decorators:[{type:o,args:[{selector:"tb-kv-map-config",templateUrl:"./kv-map-config.component.html",styleUrls:["./kv-map-config.component.scss"],providers:[{provide:S,useExisting:n((()=>bt)),multi:!0},{provide:A,useExisting:n((()=>bt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:t.Injector},{type:k.FormBuilder}]},propDecorators:{disabled:[{type:l}],requiredText:[{type:l}],keyText:[{type:l}],keyRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],required:[{type:l}]}});class ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=Xe,this.ToByteStandartCharsetTypeTranslationMap=Ze}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[M.required]],bootstrapServers:[e?e.bootstrapServers:null,[M.required]],retries:[e?e.retries:null,[M.min(0)]],batchSize:[e?e.batchSize:null,[M.min(0)]],linger:[e?e.linger:null,[M.min(0)]],bufferMemory:[e?e.bufferMemory:null,[M.min(0)]],acks:[e?e.acks:null,[M.required]],keySerializer:[e?e.keySerializer:null,[M.required]],valueSerializer:[e?e.valueSerializer:null,[M.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([M.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",ht),ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ht,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:ht,selector:"tb-action-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ht,decorators:[{type:o,args:[{selector:"tb-action-node-kafka-config",templateUrl:"./kafka-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Ct extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[M.required]]})}testScript(){const e=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((e=>{e&&this.logConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",Ct),Ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ct,deps:[{token:T.Store},{token:k.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Ct,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:W.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ct,decorators:[{type:o,args:[{selector:"tb-action-node-log-config",templateUrl:"./log-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Ft extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Qe,this.credentialsTypeTranslationsMap=$e,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[M.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(me()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const o=e[t];if(!o.firstChange&&o.currentValue!==o.previousValue&&o.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){$(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([M.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[M.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(M.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return o=>{t||(t=[Object.keys(o.controls)]);return(null==o?void 0:o.controls)&&t.some((t=>t.every((t=>!e(o.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",Ft),Ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ft,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Ft,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:S,useExisting:n((()=>Ft)),multi:!0},{provide:A,useExisting:n((()=>Ft)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',components:[{type:K.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:K.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:_.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:K.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:K.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:K.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{type:D.MatLabel,selector:"mat-label"},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ft,decorators:[{type:o,args:[{selector:"tb-credentials-config",templateUrl:"./credentials-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>Ft)),multi:!0},{provide:A,useExisting:n((()=>Ft)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]},propDecorators:{required:[{type:l}],disableCertPemCredentials:[{type:l}],passwordFieldRquired:[{type:l}]}});class Lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[M.required]],host:[e?e.host:null,[M.required]],port:[e?e.port:null,[M.required,M.min(1),M.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[M.required,M.min(1),M.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&Y(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{Y(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Lt),Lt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Lt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Lt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Lt,selector:"tb-action-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}:host mat-checkbox{padding-bottom:16px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:Ft,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Lt,decorators:[{type:o,args:[{selector:"tb-action-node-mqtt-config",templateUrl:"./mqtt-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[M.required,M.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[M.required]]})}}e("MsgCountConfigComponent",vt),vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:vt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:vt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:vt,decorators:[{type:o,args:[{selector:"tb-action-node-msg-count-config",templateUrl:"./msg-count-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class It extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[M.required,M.min(1),M.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([M.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([M.required,M.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",It),It.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:It,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),It.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:It,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:k.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:It,decorators:[{type:o,args:[{selector:"tb-action-node-msg-delay-config",templateUrl:"./msg-delay-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[M.required]],topicName:[e?e.topicName:null,[M.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[M.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[M.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",Nt),Nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Nt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Nt,selector:"tb-action-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:_.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Nt,decorators:[{type:o,args:[{selector:"tb-action-node-pub-sub-config",templateUrl:"./pubsub-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[M.required]]})}}e("PushToCloudConfigComponent",Tt),Tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Tt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Tt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Tt,decorators:[{type:o,args:[{selector:"tb-action-node-push-to-cloud-config",templateUrl:"./push-to-cloud-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[M.required]]})}}e("PushToEdgeConfigComponent",kt),kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:kt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:kt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:kt,decorators:[{type:o,args:[{selector:"tb-action-node-push-to-edge-config",templateUrl:"./push-to-edge-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[M.required]],port:[e?e.port:null,[M.required,M.min(1),M.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[M.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[M.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Mt),Mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Mt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Mt,selector:"tb-action-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Mt,decorators:[{type:o,args:[{selector:"tb-action-node-rabbit-mq-config",templateUrl:"./rabbit-mq-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class qt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Je)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[M.required]],requestMethod:[e?e.requestMethod:null,[M.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[M.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,o=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[M.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[M.required,M.min(1),M.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([M.min(0)])),o?this.restApiCallConfigForm.get("maxQueueSize").setValidators([M.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",qt),qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:qt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:qt,selector:"tb-action-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{type:Ft,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:qt,decorators:[{type:o,args:[{selector:"tb-action-node-rest-api-call-config",templateUrl:"./rest-api-call-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class St extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",St),St.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:St,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),St.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:St,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:St,decorators:[{type:o,args:[{selector:"tb-action-node-rpc-reply-config",templateUrl:"./rpc-reply-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class At extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[M.required,M.min(0)]]})}}e("RpcRequestConfigComponent",At),At.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:At,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),At.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:At,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:At,decorators:[{type:o,args:[{selector:"tb-action-node-rpc-request-config",templateUrl:"./rpc-request-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[M.required,M.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[M.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Gt),Gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Gt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Gt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Gt,decorators:[{type:o,args:[{selector:"tb-action-node-custom-table-config",templateUrl:"./save-to-custom-table-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,o=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([M.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([M.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([M.required,M.min(1),M.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([M.required,M.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(o?[M.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(o?[M.required,M.min(1),M.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Dt),Dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Dt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Dt,selector:"tb-action-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ge.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Dt,decorators:[{type:o,args:[{selector:"tb-action-node-send-email-config",templateUrl:"./send-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[M.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[M.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([M.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Et),Et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Et,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Et,selector:"tb-action-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:xe.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Et,decorators:[{type:o,args:[{selector:"tb-action-node-send-sms-config",templateUrl:"./send-sms-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[M.required]],accessKeyId:[e?e.accessKeyId:null,[M.required]],secretAccessKey:[e?e.secretAccessKey:null,[M.required]],region:[e?e.region:null,[M.required]]})}}e("SnsConfigComponent",Vt),Vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Vt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Vt,selector:"tb-action-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Vt,decorators:[{type:o,args:[{selector:"tb-action-node-sns-config",templateUrl:"./sns-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=_e,this.sqsQueueTypes=Object.keys(_e),this.sqsQueueTypeTranslationsMap=ze}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[M.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[M.required]],delaySeconds:[e?e.delaySeconds:null,[M.min(0),M.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[M.required]],secretAccessKey:[e?e.secretAccessKey:null,[M.required]],region:[e?e.region:null,[M.required]]})}}e("SqsConfigComponent",Pt),Pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Pt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Pt,selector:"tb-action-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Pt,decorators:[{type:o,args:[{selector:"tb-action-node-sqs-config",templateUrl:"./sqs-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[M.required,M.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Rt),Rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Rt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Rt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Rt,decorators:[{type:o,args:[{selector:"tb-action-node-timeseries-config",templateUrl:"./timeseries-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[M.required,M.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[M.required,M.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Ot),Ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ot,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Ot,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ot,decorators:[{type:o,args:[{selector:"tb-action-node-un-assign-to-customer-config",templateUrl:"./unassign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class wt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.injector=o,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...tt.values()],this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(ue((e=>{let t;t="string"==typeof e&&et[e]?et[e]:null,this.updateView(t)})),pe((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=tt.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",wt),wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:wt,deps:[{token:T.Store},{token:P.TranslateService},{token:t.Injector},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:wt,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:S,useExisting:n((()=>wt)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ye.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:ye.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatSuffix,selector:"[matSuffix]"},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{async:O.AsyncPipe,highlight:be.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:wt,decorators:[{type:o,args:[{selector:"tb-math-function-autocomplete",templateUrl:"./math-function-autocomplete.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>wt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:t.Injector},{type:k.FormBuilder}]},propDecorators:{required:[{type:l}],disabled:[{type:l}],operationInput:[{type:a,args:["operationInput",{static:!0}]}]}});class Ht extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.injector=o,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=tt,this.ArgumentType=ot,this.attributeScopeMap=st,this.argumentTypeResultMap=at,this.arguments=Object.values(ot),this.attributeScope=Object.values(lt),this.propagateChange=null,this.valueChangeSubscription=[]}get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup())}ngOnInit(){this.ngControl=this.injector.get(q),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({}),this.argumentsFormGroup.addControl("arguments",this.fb.array([])),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),o=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,o),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):this.argumentsFormGroup.enable({emitEvent:!1})}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()));const t=[];e&&e.forEach(((e,o)=>{t.push(this.createArgumentControl(e,o))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t)),this.setupArgumentsFormGroup(),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()})))}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(){const e=this.argumentsFormGroup.get("arguments"),t=this.createArgumentControl(null,e.length);e.push(t)}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===et.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([M.minLength(this.minArgs),M.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(o),o.get("attributeScope").updateValueAndValidity({emitEvent:!0}),o.get("defaultValue").updateValueAndValidity({emitEvent:!0})}))),o}updateArgumentControlValidators(e){const t=e.get("type").value;t===ot.ATTRIBUTE?e.get("attributeScope").enable():e.get("attributeScope").disable(),t&&t!==ot.CONSTANT?e.get("defaultValue").enable():e.get("defaultValue").disable()}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(nt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ht,deps:[{token:T.Store},{token:P.TranslateService},{token:t.Injector},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Ht,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:S,useExisting:n((()=>Ht)),multi:!0},{provide:A,useExisting:n((()=>Ht)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host mat-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"],components:[{type:he.MatList,selector:"mat-list, mat-action-list",inputs:["disableRipple","disabled"],exportAs:["matList"]},{type:he.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["disableRipple","disabled"],exportAs:["matListItem"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:O.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{type:re.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{type:Ce.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","id","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListAutoScrollDisabled","cdkDropListOrientation","cdkDropListLockAxis","cdkDropListData","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:k.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{type:Ce.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragDisabled","cdkDragStartDelay","cdkDragLockAxis","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragBoundary","cdkDragRootElement","cdkDragPreviewContainer","cdkDragData","cdkDragFreeDragPosition"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:V.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:Ce.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{type:se.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ht,decorators:[{type:o,args:[{selector:"tb-arguments-map-config",templateUrl:"./arguments-map-config.component.html",styleUrls:["./arguments-map-config.component.scss"],providers:[{provide:S,useExisting:n((()=>Ht)),multi:!0},{provide:A,useExisting:n((()=>Ht)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:t.Injector},{type:k.FormBuilder}]},propDecorators:{disabled:[{type:l}],function:[{type:l}]}});class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=et,this.ArgumentTypeResult=rt,this.argumentTypeResultMap=at,this.attributeScopeMap=st,this.argumentsResult=Object.values(rt),this.attributeScopeResult=Object.values(it)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[M.required]],arguments:[e?e.arguments:null,[M.required]],customFunction:[e?e.customFunction:"",[M.required]],result:this.fb.group({type:[e?e.result.type:null,[M.required]],attributeScope:[e?e.result.attributeScope:null],key:[e?e.result.key:"",[M.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,o=this.mathFunctionConfigForm.get("result").get("type").value;t===et.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),o===rt.ATTRIBUTE?this.mathFunctionConfigForm.get("result").get("attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result").get("attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result").get("attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ut,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Ut,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],components:[{type:wt,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{type:Ht,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:k.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{type:D.MatLabel,selector:"mat-label"},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:V.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Ut,decorators:[{type:o,args:[{selector:"tb-action-node-math-function-config",templateUrl:"./math-function-config.component.html",styleUrls:["./math-function-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Bt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[M.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[M.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Bt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Bt,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:S,useExisting:n((()=>Bt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:Le.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]},{type:ve.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Bt,decorators:[{type:o,args:[{selector:"tb-device-relations-query-config",templateUrl:"./device-relations-query-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>Bt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class Kt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[M.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Kt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Kt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:S,useExisting:n((()=>Kt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:Ie.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Kt,decorators:[{type:o,args:[{selector:"tb-relations-query-config",templateUrl:"./relations-query-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>Kt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class jt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.truncate=o,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[X,Z,ee],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(b))this.messageTypesList.push({name:h.get(b[e]),value:e})}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(de(""),pe((e=>e||"")),fe((e=>this.fetchMessageTypes(e))),ce())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ne(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const o=e.trim(),r=this.messageTypesList.find((e=>e.name===o));t=r?{name:r.name,value:r.value}:{name:o,value:o},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:jt,deps:[{token:T.Store},{token:P.TranslateService},{token:C.TruncatePipe},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:jt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:S,useExisting:n((()=>jt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ye.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:ye.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:ye.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,async:O.AsyncPipe,highlight:be.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:jt,decorators:[{type:o,args:[{selector:"tb-message-types-config",templateUrl:"./message-types-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>jt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:C.TruncatePipe},{type:k.FormBuilder}]},propDecorators:{required:[{type:l}],label:[{type:l}],placeholder:[{type:l}],disabled:[{type:l}],chipList:[{type:a,args:["chipList",{static:!1}]}],matAutocomplete:[{type:a,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:a,args:["messageTypeInput",{static:!1}]}]}});class _t{}e("RulenodeCoreConfigCommonModule",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:_t,deps:[],target:t.ɵɵFactoryTarget.NgModule}),_t.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:_t,declarations:[bt,Bt,Kt,jt,Ft,Se,Ht,wt],imports:[w,F,Fe],exports:[bt,Bt,Kt,jt,Ft,Se,Ht,wt]}),_t.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:_t,imports:[[w,F,Fe]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:_t,decorators:[{type:i,args:[{declarations:[bt,Bt,Kt,jt,Ft,Se,Ht,wt],imports:[w,F,Fe],exports:[bt,Bt,Kt,jt,Ft,Se,Ht,wt]}]}]});class zt{}e("RuleNodeCoreConfigActionModule",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:zt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:zt,declarations:[Ge,Rt,At,Ct,Ae,pt,dt,ft,It,ct,xt,yt,vt,St,Gt,Ot,Vt,Pt,Nt,ht,Lt,Mt,qt,Dt,ut,mt,gt,Et,kt,Tt,Ut],imports:[w,F,Fe,_t],exports:[Ge,Rt,At,Ct,Ae,pt,dt,ft,It,ct,xt,yt,vt,St,Gt,Ot,Vt,Pt,Nt,ht,Lt,Mt,qt,Dt,ut,mt,gt,Et,kt,Tt,Ut]}),zt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:zt,imports:[[w,F,Fe,_t]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:zt,decorators:[{type:i,args:[{declarations:[Ge,Rt,At,Ct,Ae,pt,dt,ft,It,ct,xt,yt,vt,St,Gt,Ot,Vt,Pt,Nt,ht,Lt,Mt,qt,Dt,ut,mt,gt,Et,kt,Tt,Ut],imports:[w,F,Fe,_t],exports:[Ge,Rt,At,Ct,Ae,pt,dt,ft,It,ct,xt,yt,vt,St,Gt,Ot,Vt,Pt,Nt,ht,Lt,Mt,qt,Dt,ut,mt,gt,Et,kt,Tt,Ut]}]}]});class Qt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[X,Z,ee]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[M.required]],outputValueKey:[e?e.outputValueKey:null,[M.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[M.min(0),M.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([M.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Qt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Qt,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Qt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-calculate-delta-config",templateUrl:"./calculate-delta-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[M.required]]})}}e("CustomerAttributesConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:$t,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:$t,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:$t,decorators:[{type:o,args:[{selector:"tb-enrichment-node-customer-attributes-config",templateUrl:"./customer-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[X,Z,ee]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[M.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.deviceAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.deviceAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("DeviceAttributesConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Yt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Yt,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:Bt,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Yt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-device-attributes-config",templateUrl:"./device-attributes-config.component.html",styleUrls:["./device-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Wt extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.entityDetailsTranslationsMap=Be,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(Ue))this.entityDetailsList.push(Ue[e]);this.detailsFormControl=new G(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(de(""),pe((e=>e||"")),fe((e=>this.fetchEntityDetails(e))),ce())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[M.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})}displayDetails(e){return e?this.translate.instant(Be.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(this.entityDetailsList.filter((t=>this.translate.instant(Be.get(Ue[t])).toUpperCase().includes(e))))}return Ne(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.entityDetailsConfigForm.get("detailsList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}}addDetailsField(e){let t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Wt,deps:[{token:T.Store},{token:P.TranslateService},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Wt,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ye.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:ye.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:ye.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe,async:O.AsyncPipe,highlight:be.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Wt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-entity-details-config",templateUrl:"./entity-details-config.component.html",styleUrls:["./entity-details-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:k.FormBuilder}]},propDecorators:{detailsInput:[{type:a,args:["detailsInput",{static:!1}]}]}});class Jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[X,Z,ee],this.aggregationTypes=L,this.aggregations=Object.keys(L),this.aggregationTypesTranslations=v,this.fetchMode=Ke,this.fetchModes=Object.keys(Ke),this.samplingOrders=Object.keys(je),this.timeUnits=Object.values(Re),this.timeUnitsTranslationMap=Oe}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[M.required]],fetchMode:[e?e.fetchMode:null,[M.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,o=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===Ke.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([M.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([M.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([M.required,M.min(2),M.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),o?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([M.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([M.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([M.required,M.min(1),M.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([M.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([M.required,M.min(1),M.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([M.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const o=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Jt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Jt,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Jt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",templateUrl:"./get-telemetry-from-database-config.component.html",styleUrls:["./get-telemetry-from-database-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[X,Z,ee]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.originatorAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.originatorAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("OriginatorAttributesConfigComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Xt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Xt,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Xt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-originator-attributes-config",templateUrl:"./originator-attributes-config.component.html",styleUrls:["./originator-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[M.required]],ignoreNullStrings:[e?e.ignoreNullStrings:null]})}}e("OriginatorFieldsConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Zt,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:Zt,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n {{ "tb.rulenode.ignore-null-strings" | translate }}\n
{{ "tb.rulenode.ignore-null-strings-hint" | translate }}
\n
\n',components:[{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Zt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-originator-fields-config",templateUrl:"./originator-fields-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class eo extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[M.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[M.required]]})}}e("RelatedAttributesConfigComponent",eo),eo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:eo,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),eo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:eo,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:Kt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:eo,decorators:[{type:o,args:[{selector:"tb-enrichment-node-related-attributes-config",templateUrl:"./related-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class to extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[M.required]]})}}e("TenantAttributesConfigComponent",to),to.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:to,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),to.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:to,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:bt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:to,decorators:[{type:o,args:[{selector:"tb-enrichment-node-tenant-attributes-config",templateUrl:"./tenant-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class oo extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchToMetadata:[e?e.fetchToMetadata:null,[]]})}}e("FetchDeviceCredentialsConfigComponent",oo),oo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:oo,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),oo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:oo,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n {{ \'tb.rulenode.fetch-credentials-to-metadata\' | translate }}\n
\n',components:[{type:Te.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex","name","id","labelPosition","aria-label","aria-labelledby","required","checked","aria-describedby"],outputs:["change","toggleChange"],exportAs:["matSlideToggle"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:oo,decorators:[{type:o,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",templateUrl:"./fetch-device-credentials-config.component.html"}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class ro{}e("RulenodeCoreConfigEnrichmentModule",ro),ro.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ro,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ro.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ro,declarations:[$t,Wt,Yt,Xt,Zt,Jt,eo,to,Qt,oo],imports:[w,F,_t],exports:[$t,Wt,Yt,Xt,Zt,Jt,eo,to,Qt,oo]}),ro.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ro,imports:[[w,F,_t]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ro,decorators:[{type:i,args:[{declarations:[$t,Wt,Yt,Xt,Zt,Jt,eo,to,Qt,oo],imports:[w,F,_t],exports:[$t,Wt,Yt,Xt,Zt,Jt,eo,to,Qt,oo]}]}]});class ao extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.alarmStatusTranslationsMap=I,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(N))this.alarmStatusList.push(N[e]);this.statusFormControl=new G(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(de(""),pe((e=>e||"")),fe((e=>this.fetchAlarmStatus(e))),ce())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[M.required]]})}displayStatus(e){return e?this.translate.instant(I.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(t.filter((t=>this.translate.instant(I.get(N[t])).toUpperCase().includes(e))))}return Ne(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",ao),ao.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ao,deps:[{token:T.Store},{token:P.TranslateService},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ao.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:ao,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ye.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:ye.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:ye.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe,async:O.AsyncPipe,highlight:be.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ao,decorators:[{type:o,args:[{selector:"tb-filter-node-check-alarm-status-config",templateUrl:"./check-alarm-status.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:k.FormBuilder}]},propDecorators:{alarmStatusInput:[{type:a,args:["alarmStatusInput",{static:!1}]}]}});class no extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[X,Z,ee]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",no),no.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:no,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),no.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:no,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:no,decorators:[{type:o,args:[{selector:"tb-filter-node-check-message-config",templateUrl:"./check-message-config.component.html",styleUrls:["./check-message-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class lo extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(c),this.entitySearchDirectionTranslationsMap=g}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[M.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[M.required]:[]],relationType:[e?e.relationType:null,[M.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[M.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[M.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",lo),lo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:lo,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),lo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:lo,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',components:[{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{type:ke.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]},{type:Le.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:lo,decorators:[{type:o,args:[{selector:"tb-filter-node-check-relation-config",templateUrl:"./check-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class io extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Ve,this.perimeterTypes=Object.keys(Ve),this.perimeterTypeTranslationMap=Pe,this.rangeUnits=Object.keys(we),this.rangeUnitTranslationMap=He}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[M.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[M.required]],perimeterType:[e?e.perimeterType:null,[M.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([M.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||o!==Ve.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([M.required,M.min(-90),M.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([M.required,M.min(-180),M.max(180)]),this.geoFilterConfigForm.get("range").setValidators([M.required,M.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([M.required])),t||o!==Ve.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([M.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",io),io.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:io,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),io.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:io,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:E.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:k.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:k.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:k.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:io,decorators:[{type:o,args:[{selector:"tb-filter-node-gps-geofencing-config",templateUrl:"./gps-geo-filter-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class so extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[M.required]]})}}e("MessageTypeConfigComponent",so),so.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:so,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),so.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:so,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',components:[{type:jt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:so,decorators:[{type:o,args:[{selector:"tb-filter-node-message-type-config",templateUrl:"./message-type-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class mo extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[M.required]]})}}e("OriginatorTypeConfigComponent",mo),mo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:mo,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:mo,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"],components:[{type:Me.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","allowedEntityTypes","ignoreAuthorityFilter"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:mo,decorators:[{type:o,args:[{selector:"tb-filter-node-originator-type-config",templateUrl:"./originator-type-config.component.html",styleUrls:["./originator-type-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class uo extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[M.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",uo),uo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:uo,deps:[{token:T.Store},{token:k.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),uo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:uo,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:W.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:uo,decorators:[{type:o,args:[{selector:"tb-filter-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class po extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[M.required]]})}testScript(){const e=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((e=>{e&&this.switchConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",po),po.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:po,deps:[{token:T.Store},{token:k.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),po.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:po,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:W.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:po,decorators:[{type:o,args:[{selector:"tb-filter-node-switch-config",templateUrl:"./switch-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class fo{}e("RuleNodeCoreConfigFilterModule",fo),fo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:fo,deps:[],target:t.ɵɵFactoryTarget.NgModule}),fo.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:fo,declarations:[no,lo,io,so,mo,uo,po,ao],imports:[w,F,_t],exports:[no,lo,io,so,mo,uo,po,ao]}),fo.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:fo,imports:[[w,F,_t]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:fo,decorators:[{type:i,args:[{declarations:[no,lo,io,so,mo,uo,po,ao],imports:[w,F,_t],exports:[no,lo,io,so,mo,uo,po,ao]}]}]});class co extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=De,this.originatorSources=Object.keys(De),this.originatorSourceTranslationMap=Ee}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[M.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===De.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([M.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===De.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([M.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([M.required,M.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",co),co.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:co,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),co.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:co,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{type:Kt,selector:"tb-relations-query-config",inputs:["disabled","required"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:V.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:V.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:co,decorators:[{type:o,args:[{selector:"tb-transformation-node-change-originator-config",templateUrl:"./change-originator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class go extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[M.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",go),go.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:go,deps:[{token:T.Store},{token:k.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),go.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:go,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:W.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:go,decorators:[{type:o,args:[{selector:"tb-transformation-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class xo extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[M.required]],toTemplate:[e?e.toTemplate:null,[M.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[M.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[M.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(de([null==e?void 0:e.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(M.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",xo),xo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:xo,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:xo,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:B.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:k.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe,safeHtml:Se}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:xo,decorators:[{type:o,args:[{selector:"tb-transformation-node-to-email-config",templateUrl:"./to-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class yo{}e("RulenodeCoreConfigTransformModule",yo),yo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:yo,deps:[],target:t.ɵɵFactoryTarget.NgModule}),yo.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:yo,declarations:[co,go,xo],imports:[w,F,_t],exports:[co,go,xo]}),yo.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:yo,imports:[[w,F,_t]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:yo,decorators:[{type:i,args:[{declarations:[co,go,xo],imports:[w,F,_t],exports:[co,go,xo]}]}]});class bo extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[M.required]]})}}e("RuleChainInputComponent",bo),bo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:bo,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:bo,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',components:[{type:ke.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]}],directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:k.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:k.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:k.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:bo,decorators:[{type:o,args:[{selector:"tb-flow-node-rule-chain-input-config",templateUrl:"./rule-chain-input.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class ho extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",ho),ho.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ho,deps:[{token:T.Store},{token:k.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ho.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.16",type:ho,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',directives:[{type:V.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:k.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:k.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:ho,decorators:[{type:o,args:[{selector:"tb-flow-node-rule-chain-output-config",templateUrl:"./rule-chain-output.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:k.FormBuilder}]}});class Co{}e("RuleNodeCoreConfigFlowModule",Co),Co.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Co,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Co.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Co,declarations:[bo,ho],imports:[w,F,_t],exports:[bo,ho]}),Co.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Co,imports:[[w,F,_t]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Co,decorators:[{type:i,args:[{declarations:[bo,ho],imports:[w,F,_t],exports:[bo,ho]}]}]});class Fo{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body to substitute "Source" and "Target" key names',"shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",Fo),Fo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Fo,deps:[{token:P.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),Fo.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Fo,declarations:[qe],imports:[w,F],exports:[zt,fo,ro,yo,Co,qe]}),Fo.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Fo,imports:[[w,F],zt,fo,ro,yo,Co]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.16",ngImport:t,type:Fo,decorators:[{type:i,args:[{declarations:[qe],imports:[w,F],exports:[zt,fo,ro,yo,Co,qe]}]}],ctorParameters:function(){return[{type:P.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map diff --git a/rule-engine/rule-engine-components/src/test/java/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/math/TbMathNodeTest.java new file mode 100644 index 0000000000..5a0cf6eb91 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/math/TbMathNodeTest.java @@ -0,0 +1,339 @@ +/** + * Copyright © 2016-2022 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 math; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.google.common.util.concurrent.Futures; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.common.util.AbstractListeningExecutor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.math.TbMathArgument; +import org.thingsboard.rule.engine.math.TbMathArgumentType; +import org.thingsboard.rule.engine.math.TbMathNode; +import org.thingsboard.rule.engine.math.TbMathNodeConfiguration; +import org.thingsboard.rule.engine.math.TbMathResult; +import org.thingsboard.rule.engine.math.TbRuleNodeMathFunctionType; +import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.timeseries.TimeseriesService; + +import java.util.Arrays; +import java.util.Optional; + +import static org.mockito.Mockito.lenient; + +@RunWith(MockitoJUnitRunner.class) +public class TbMathNodeTest { + + private EntityId originator = new DeviceId(Uuids.timeBased()); + private TenantId tenantId = TenantId.fromUUID(Uuids.timeBased()); + + @Mock + private TbContext ctx; + @Mock + private AttributesService attributesService; + @Mock + private TimeseriesService tsService; + + private AbstractListeningExecutor dbExecutor; + + @Before + public void before() { + dbExecutor = new AbstractListeningExecutor() { + @Override + protected int getThreadPollSize() { + return 3; + } + }; + dbExecutor.init(); + initMocks(); + } + + @After + public void after() { + dbExecutor.destroy(); + } + + private void initMocks() { + Mockito.reset(ctx); + Mockito.reset(attributesService); + Mockito.reset(tsService); + lenient().when(ctx.getAttributesService()).thenReturn(attributesService); + lenient().when(ctx.getTimeseriesService()).thenReturn(tsService); + lenient().when(ctx.getTenantId()).thenReturn(tenantId); + lenient().when(ctx.getDbCallbackExecutor()).thenReturn(dbExecutor); + } + + private TbMathNode initNode(TbRuleNodeMathFunctionType operation, TbMathResult result, TbMathArgument... arguments) { + return initNode(operation, null, result, arguments); + } + + private TbMathNode initNodeWithCustomFunction(String expression, TbMathResult result, TbMathArgument... arguments) { + return initNode(TbRuleNodeMathFunctionType.CUSTOM, expression, result, arguments); + } + + private TbMathNode initNode(TbRuleNodeMathFunctionType operation, String expression, TbMathResult result, TbMathArgument... arguments) { + try { + TbMathNodeConfiguration configuration = new TbMathNodeConfiguration(); + configuration.setOperation(operation); + if (TbRuleNodeMathFunctionType.CUSTOM.equals(operation)) { + configuration.setCustomFunction(expression); + } + configuration.setResult(result); + configuration.setArguments(Arrays.asList(arguments)); + TbMathNode node = new TbMathNode(); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(configuration))); + return node; + } catch (TbNodeException ex) { + throw new IllegalStateException(ex); + } + } + + @Test + public void testExp4j() { + var node = initNodeWithCustomFunction("2a+3b", + new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "result", 2, false, false, null), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a"), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") + ); + + TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + + node.onMsg(ctx, msg); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + Mockito.verify(ctx, Mockito.timeout(5000)).tellSuccess(msgCaptor.capture()); + + TbMsg resultMsg = msgCaptor.getValue(); + Assert.assertNotNull(resultMsg); + Assert.assertNotNull(resultMsg.getData()); + var resultJson = JacksonUtil.toJsonNode(resultMsg.getData()); + Assert.assertTrue(resultJson.has("result")); + Assert.assertEquals(10, resultJson.get("result").asInt()); + } + + @Test + public void testSimpleFunctions() { + testSimpleTwoArgumentFunction(TbRuleNodeMathFunctionType.ADD, 2.1, 2.2, 4.3); + testSimpleTwoArgumentFunction(TbRuleNodeMathFunctionType.SUB, 2.1, 2.2, -0.1); + testSimpleTwoArgumentFunction(TbRuleNodeMathFunctionType.MULT, 2.1, 2.0, 4.2); + testSimpleTwoArgumentFunction(TbRuleNodeMathFunctionType.DIV, 4.2, 2.0, 2.1); + + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.SIN, Math.toRadians(30), 0.5); + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.SIN, Math.toRadians(90), 1.0); + + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.SINH, Math.toRadians(0), 0.0); + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.COSH, Math.toRadians(0), 1.0); + + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.COS, Math.toRadians(60), 0.5); + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.COS, Math.toRadians(0), 1.0); + + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.TAN, Math.toRadians(45), 1); + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.TAN, Math.toRadians(0), 0); + + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.ABS, -1, 1); + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.SQRT, 4, 2); + testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType.CBRT, 8, 2); + } + + private void testSimpleTwoArgumentFunction(TbRuleNodeMathFunctionType function, double arg1, double arg2, double result) { + initMocks(); + + var node = initNode(function, + new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "result", 2, false, false, null), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a"), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") + ); + + TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", arg1).put("b", arg2).toString()); + + node.onMsg(ctx, msg); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + Mockito.verify(ctx, Mockito.timeout(5000).times(1)).tellSuccess(msgCaptor.capture()); + + TbMsg resultMsg = msgCaptor.getValue(); + Assert.assertNotNull(resultMsg); + Assert.assertNotNull(resultMsg.getData()); + var resultJson = JacksonUtil.toJsonNode(resultMsg.getData()); + Assert.assertTrue(resultJson.has("result")); + Assert.assertEquals(result, resultJson.get("result").asDouble(), 0d); + } + + private void testSimpleOneArgumentFunction(TbRuleNodeMathFunctionType function, double arg1, double result) { + initMocks(); + + var node = initNode(function, + new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "result", 2, false, false, null), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") + ); + + TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", arg1).toString()); + + node.onMsg(ctx, msg); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + Mockito.verify(ctx, Mockito.timeout(5000)).tellSuccess(msgCaptor.capture()); + + TbMsg resultMsg = msgCaptor.getValue(); + Assert.assertNotNull(resultMsg); + Assert.assertNotNull(resultMsg.getData()); + var resultJson = JacksonUtil.toJsonNode(resultMsg.getData()); + Assert.assertTrue(resultJson.has("result")); + Assert.assertEquals(result, resultJson.get("result").asDouble(), 0d); + } + + @Test + public void test_2_plus_2_body() { + var node = initNode(TbRuleNodeMathFunctionType.ADD, + new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "result", 2, false, false, null), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a"), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") + ); + + TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + + node.onMsg(ctx, msg); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + Mockito.verify(ctx, Mockito.timeout(5000)).tellSuccess(msgCaptor.capture()); + + TbMsg resultMsg = msgCaptor.getValue(); + Assert.assertNotNull(resultMsg); + Assert.assertNotNull(resultMsg.getData()); + var resultJson = JacksonUtil.toJsonNode(resultMsg.getData()); + Assert.assertTrue(resultJson.has("result")); + Assert.assertEquals(4, resultJson.get("result").asInt()); + } + + @Test + public void test_2_plus_2_meta() { + var node = initNode(TbRuleNodeMathFunctionType.ADD, + new TbMathResult(TbMathArgumentType.MESSAGE_METADATA, "result", 0, false, false, null), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a"), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") + ); + + TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + + node.onMsg(ctx, msg); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + Mockito.verify(ctx, Mockito.timeout(5000)).tellSuccess(msgCaptor.capture()); + + TbMsg resultMsg = msgCaptor.getValue(); + Assert.assertNotNull(resultMsg); + Assert.assertNotNull(resultMsg.getData()); + Assert.assertNotNull(resultMsg.getMetaData()); + var result = resultMsg.getMetaData().getValue("result"); + Assert.assertNotNull(result); + Assert.assertEquals("4", result); + } + + @Test + public void test_2_plus_2_attr_and_ts() { + var node = initNode(TbRuleNodeMathFunctionType.ADD, + new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "result", 2, false, false, null), + new TbMathArgument(TbMathArgumentType.ATTRIBUTE, "a"), + new TbMathArgument(TbMathArgumentType.TIME_SERIES, "b") + ); + + TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().toString()); + + Mockito.when(attributesService.find(tenantId, originator, DataConstants.SERVER_SCOPE, "a")) + .thenReturn(Futures.immediateFuture(Optional.of(new BaseAttributeKvEntry(System.currentTimeMillis(), new DoubleDataEntry("a", 2.0))))); + + Mockito.when(tsService.findLatest(tenantId, originator, "b")) + .thenReturn(Futures.immediateFuture(Optional.of(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry("b", 2L))))); + + node.onMsg(ctx, msg); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + Mockito.verify(ctx, Mockito.timeout(5000)).tellSuccess(msgCaptor.capture()); + + TbMsg resultMsg = msgCaptor.getValue(); + Assert.assertNotNull(resultMsg); + Assert.assertNotNull(resultMsg.getData()); + var resultJson = JacksonUtil.toJsonNode(resultMsg.getData()); + Assert.assertTrue(resultJson.has("result")); + Assert.assertEquals(4, resultJson.get("result").asInt()); + } + + @Test + public void test_sqrt_5_body() { + var node = initNode(TbRuleNodeMathFunctionType.SQRT, + new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "result", 3, false, false, null), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") + ); + + TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + + node.onMsg(ctx, msg); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + Mockito.verify(ctx, Mockito.timeout(5000)).tellSuccess(msgCaptor.capture()); + + TbMsg resultMsg = msgCaptor.getValue(); + Assert.assertNotNull(resultMsg); + Assert.assertNotNull(resultMsg.getData()); + var resultJson = JacksonUtil.toJsonNode(resultMsg.getData()); + Assert.assertTrue(resultJson.has("result")); + Assert.assertEquals(2.236, resultJson.get("result").asDouble(), 0.0); + } + + @Test + public void test_sqrt_5_meta() { + var node = initNode(TbRuleNodeMathFunctionType.SQRT, + new TbMathResult(TbMathArgumentType.MESSAGE_METADATA, "result", 3, false, false, null), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") + ); + + TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + + node.onMsg(ctx, msg); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + Mockito.verify(ctx, Mockito.timeout(5000)).tellSuccess(msgCaptor.capture()); + + TbMsg resultMsg = msgCaptor.getValue(); + Assert.assertNotNull(resultMsg); + Assert.assertNotNull(resultMsg.getData()); + var result = resultMsg.getMetaData().getValue("result"); + Assert.assertNotNull(result); + Assert.assertEquals("2.236", result); + } + +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesTest.java new file mode 100644 index 0000000000..8972a3aa1f --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesTest.java @@ -0,0 +1,125 @@ +/** + * Copyright © 2016-2022 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.telemetry; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.willAnswer; +import static org.mockito.BDDMockito.willReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@Slf4j +public class TbMsgDeleteAttributesTest { + final ObjectMapper mapper = new ObjectMapper(); + + DeviceId deviceId; + TbMsgDeleteAttributes node; + TbMsgDeleteAttributesConfiguration config; + TbNodeConfiguration nodeConfiguration; + TbContext ctx; + TbMsgCallback callback; + + RuleEngineTelemetryService telemetryService; + + @BeforeEach + void setUp() throws TbNodeException { + deviceId = new DeviceId(UUID.randomUUID()); + callback = mock(TbMsgCallback.class); + ctx = mock(TbContext.class); + config = new TbMsgDeleteAttributesConfiguration().defaultConfiguration(); + config.setKeys(List.of("${TestAttribute_1}", "$[TestAttribute_2]", "$[TestAttribute_3]", "TestAttribute_4")); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + node = spy(new TbMsgDeleteAttributes()); + node.init(ctx, nodeConfiguration); + telemetryService = mock(RuleEngineTelemetryService.class); + + willReturn(telemetryService).given(ctx).getTelemetryService(); + willAnswer(invocation -> { + TelemetryNodeCallback callBack = invocation.getArgument(4); + callBack.onSuccess(null); + return null; + }).given(telemetryService).deleteAndNotify( + any(), any(), anyString(), anyList(), any()); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenDefaultConfig_whenVerify_thenOK() { + TbMsgDeleteAttributesConfiguration defaultConfig = new TbMsgDeleteAttributesConfiguration().defaultConfiguration(); + assertThat(defaultConfig.getScope()).isEqualTo(DataConstants.SERVER_SCOPE); + assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptyList()); + } + + @Test + void givenMsg_whenOnMsg_thenVerifyOutput() throws Exception { + final Map mdMap = Map.of( + "TestAttribute_1", "temperature", + "city", "NY" + ); + final TbMsgMetaData metaData = new TbMsgMetaData(mdMap); + final String data = "{\"TestAttribute_2\": \"humidity\", \"TestAttribute_3\": \"voltage\"}"; + + TbMsg msg = TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", deviceId, metaData, data, callback); + node.onMsg(ctx, msg); + + ArgumentCaptor successCaptor = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor> failureCaptor = ArgumentCaptor.forClass(Consumer.class); + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + + verify(ctx, times(1)).enqueue(any(), successCaptor.capture(), failureCaptor.capture()); + successCaptor.getValue().run(); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + + verify(ctx, times(1)).attributesDeletedActionMsg(any(), any(), anyString(), anyList()); + verify(ctx, never()).tellFailure(any(), any()); + verify(telemetryService, times(1)).deleteAndNotify(any(), any(), anyString(), anyList(), any()); + } +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java new file mode 100644 index 0000000000..5b48ae419e --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java @@ -0,0 +1,166 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class TbCopyKeysNodeTest { + final ObjectMapper mapper = new ObjectMapper(); + + DeviceId deviceId; + TbCopyKeysNode node; + TbCopyKeysNodeConfiguration config; + TbNodeConfiguration nodeConfiguration; + TbContext ctx; + TbMsgCallback callback; + + @BeforeEach + void setUp() throws TbNodeException { + deviceId = new DeviceId(UUID.randomUUID()); + callback = mock(TbMsgCallback.class); + ctx = mock(TbContext.class); + config = new TbCopyKeysNodeConfiguration().defaultConfiguration(); + config.setKeys(Set.of("TestKey_1", "TestKey_2", "TestKey_3", "(\\w*)Data(\\w*)")); + config.setFromMetadata(true); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + node = spy(new TbCopyKeysNode()); + node.init(ctx, nodeConfiguration); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenDefaultConfig_whenVerify_thenOK() { + TbCopyKeysNodeConfiguration defaultConfig = new TbCopyKeysNodeConfiguration().defaultConfiguration(); + assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptySet()); + assertThat(defaultConfig.isFromMetadata()).isEqualTo(false); + } + + @Test + void givenMsgFromMetadata_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "{}"; + node.onMsg(ctx, getTbMsg(deviceId, data)); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + JsonNode dataNode = JacksonUtil.toJsonNode(newMsg.getData()); + assertThat(dataNode.has("TestKey_1")).isEqualTo(true); + assertThat(dataNode.has("voltageDataValue")).isEqualTo(true); + } + + @Test + void givenMsgFromMsg_whenOnMsg_thenVerifyOutput() throws Exception { + config.setFromMetadata(false); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + node.init(ctx, nodeConfiguration); + + String data = "{\"DigitData\":22.5,\"TempDataValue\":10.5}"; + node.onMsg(ctx, getTbMsg(deviceId, data)); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + Map metaDataMap = newMsg.getMetaData().getData(); + assertThat(metaDataMap.containsKey("DigitData")).isEqualTo(true); + assertThat(metaDataMap.containsKey("TempDataValue")).isEqualTo(true); + } + + @Test + void givenEmptyKeys_whenOnMsg_thenVerifyOutput() throws Exception { + TbCopyKeysNodeConfiguration defaultConfig = new TbCopyKeysNodeConfiguration().defaultConfiguration(); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(defaultConfig)); + node.init(ctx, nodeConfiguration); + + String data = "{\"DigitData\":22.5,\"TempDataValue\":10.5}"; + TbMsg msg = getTbMsg(deviceId, data); + node.onMsg(ctx, msg); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + assertThat(newMsg.getMetaData()).isEqualTo(msg.getMetaData()); + } + + @Test + void givenMsgDataNotJSONObject_whenOnMsg_thenTVerifyOutput() throws Exception { + String data = "[]"; + TbMsg msg = getTbMsg(deviceId, data); + node.onMsg(ctx, msg); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + assertThat(newMsg).isSameAs(msg); + } + + private TbMsg getTbMsg(EntityId entityId, String data) { + final Map mdMap = Map.of( + "TestKey_1", "Test", + "country", "US", + "voltageDataValue", "220", + "city", "NY" + ); + return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(mdMap), data, callback); + } + +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java new file mode 100644 index 0000000000..988864610e --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java @@ -0,0 +1,149 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class TbDeleteKeysNodeTest { + final ObjectMapper mapper = new ObjectMapper(); + + DeviceId deviceId; + TbDeleteKeysNode node; + TbDeleteKeysNodeConfiguration config; + TbNodeConfiguration nodeConfiguration; + TbContext ctx; + TbMsgCallback callback; + + @BeforeEach + void setUp() throws TbNodeException { + deviceId = new DeviceId(UUID.randomUUID()); + callback = mock(TbMsgCallback.class); + ctx = mock(TbContext.class); + config = new TbDeleteKeysNodeConfiguration().defaultConfiguration(); + config.setKeys(Set.of("TestKey_1", "TestKey_2", "TestKey_3", "(\\w*)Data(\\w*)")); + config.setFromMetadata(true); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + node = spy(new TbDeleteKeysNode()); + node.init(ctx, nodeConfiguration); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenDefaultConfig_whenVerify_thenOK() { + TbDeleteKeysNodeConfiguration defaultConfig = new TbDeleteKeysNodeConfiguration().defaultConfiguration(); + assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptySet()); + assertThat(defaultConfig.isFromMetadata()).isEqualTo(false); + } + + @Test + void givenMsgFromMetadata_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "{}"; + node.onMsg(ctx, getTbMsg(deviceId, data)); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + Map metaDataMap = newMsg.getMetaData().getData(); + assertThat(metaDataMap.containsKey("TestKey_1")).isEqualTo(false); + assertThat(metaDataMap.containsKey("voltageDataValue")).isEqualTo(false); + } + + @Test + void givenMsgFromMsg_whenOnMsg_thenVerifyOutput() throws Exception { + config.setFromMetadata(false); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + node.init(ctx, nodeConfiguration); + + String data = "{\"Voltage\":22.5,\"TempDataValue\":10.5}"; + node.onMsg(ctx, getTbMsg(deviceId, data)); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + JsonNode dataNode = JacksonUtil.toJsonNode(newMsg.getData()); + assertThat(dataNode.has("TempDataValue")).isEqualTo(false); + assertThat(dataNode.has("Voltage")).isEqualTo(true); + } + + @Test + void givenEmptyKeys_whenOnMsg_thenVerifyOutput() throws Exception { + TbDeleteKeysNodeConfiguration defaultConfig = new TbDeleteKeysNodeConfiguration().defaultConfiguration(); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(defaultConfig)); + node.init(ctx, nodeConfiguration); + + String data = "{\"Voltage\":220,\"Humidity\":56}"; + node.onMsg(ctx, getTbMsg(deviceId, data)); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + assertThat(newMsg.getData()).isEqualTo(data); + } + + private TbMsg getTbMsg(EntityId entityId, String data) { + final Map mdMap = Map.of( + "TestKey_1", "Test", + "country", "US", + "voltageDataValue", "220", + "city", "NY" + ); + return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(mdMap), data, callback); + } + +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java new file mode 100644 index 0000000000..ae9a8f9fdb --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java @@ -0,0 +1,167 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.PathNotFoundException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; + +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class TbJsonPathNodeTest { + final ObjectMapper mapper = new ObjectMapper(); + + DeviceId deviceId; + TbJsonPathNode node; + TbJsonPathNodeConfiguration config; + TbNodeConfiguration nodeConfiguration; + TbContext ctx; + TbMsgCallback callback; + + @BeforeEach + void setUp() throws TbNodeException { + deviceId = new DeviceId(UUID.randomUUID()); + callback = mock(TbMsgCallback.class); + ctx = mock(TbContext.class); + config = new TbJsonPathNodeConfiguration(); + config.setJsonPath("$.Attribute_2"); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + node = spy(new TbJsonPathNode()); + node.init(ctx, nodeConfiguration); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenDefaultConfig_whenInit_thenFail() { + config.setJsonPath(""); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + assertThatThrownBy(() -> node.init(ctx, nodeConfiguration)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void givenDefaultConfig_whenVerify_thenOK() { + TbJsonPathNodeConfiguration defaultConfig = new TbJsonPathNodeConfiguration().defaultConfiguration(); + assertThat(defaultConfig.getJsonPath()).isEqualTo(TbJsonPathNodeConfiguration.DEFAULT_JSON_PATH); + } + + @Test + void givenPrimitiveMsg_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "{\"Attribute_1\":22.5,\"Attribute_2\":100}"; + VerifyOutputMsg(data, 1, 100); + + data = "{\"Attribute_1\":22.5,\"Attribute_2\":\"StringValue\"}"; + VerifyOutputMsg(data, 2, "StringValue"); + } + + @Test + void givenJsonArray_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "{\"Attribute_1\":22.5,\"Attribute_2\":[{\"Attribute_3\":22.5,\"Attribute_4\":10.3}, {\"Attribute_5\":22.5,\"Attribute_6\":10.3}]}"; + VerifyOutputMsg(data, 1, JacksonUtil.toJsonNode(data).get("Attribute_2")); + } + + @Test + void givenJsonNode_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "{\"Attribute_1\":22.5,\"Attribute_2\":{\"Attribute_3\":22.5,\"Attribute_4\":10.3}}"; + VerifyOutputMsg(data, 1, JacksonUtil.toJsonNode(data).get("Attribute_2")); + } + + @Test + void givenJsonArrayWithFilter_whenOnMsg_thenVerifyOutput() throws Exception { + config.setJsonPath("$.Attribute_2[?(@.voltage > 200)]"); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + node.init(ctx, nodeConfiguration); + + String data = "{\"Attribute_1\":22.5,\"Attribute_2\":[{\"voltage\":220}, {\"voltage\":250}, {\"voltage\":110}]}"; + VerifyOutputMsg(data, 1, JacksonUtil.toJsonNode("[{\"voltage\":220}, {\"voltage\":250}]")); + } + + @Test + void givenNoArrayMsg_whenOnMsg_thenTellFailure() throws Exception { + String data = "{\"Attribute_1\":22.5,\"Attribute_5\":10.3}"; + JsonNode dataNode = JacksonUtil.toJsonNode(data); + TbMsg msg = getTbMsg(deviceId, dataNode.toString()); + node.onMsg(ctx, msg); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); + verify(ctx, never()).tellSuccess(any()); + verify(ctx, times(1)).tellFailure(newMsgCaptor.capture(), exceptionCaptor.capture()); + + assertThat(newMsgCaptor.getValue()).isSameAs(msg); + assertThat(exceptionCaptor.getValue()).isInstanceOf(RuntimeException.class); + } + + @Test + void givenNoResultsForPath_whenOnMsg_thenTellFailure() throws Exception { + String data = "{\"Attribute_1\":22.5,\"Attribute_5\":10.3}"; + JsonNode dataNode = JacksonUtil.toJsonNode(data); + TbMsg msg = getTbMsg(deviceId, dataNode.toString()); + node.onMsg(ctx, msg); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); + verify(ctx, never()).tellSuccess(any()); + verify(ctx, times(1)).tellFailure(newMsgCaptor.capture(), exceptionCaptor.capture()); + + assertThat(newMsgCaptor.getValue()).isSameAs(msg); + assertThat(exceptionCaptor.getValue()).isInstanceOf(PathNotFoundException.class); + } + + private void VerifyOutputMsg(String data, int countTellSuccess, Object value) throws Exception { + JsonNode dataNode = JacksonUtil.toJsonNode(data); + node.onMsg(ctx, getTbMsg(deviceId, dataNode.toString())); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(countTellSuccess)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + assertThat(newMsgCaptor.getValue().getData()).isEqualTo(JacksonUtil.toString(value)); + } + + private TbMsg getTbMsg(EntityId entityId, String data) { + Map mdMap = Map.of("country", "US", + "city", "NY" + ); + return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(mdMap), data, callback); + } +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java new file mode 100644 index 0000000000..3cafbce8b2 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java @@ -0,0 +1,159 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; + +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class TbRenameKeysNodeTest { + DeviceId deviceId; + TbRenameKeysNode node; + TbRenameKeysNodeConfiguration config; + TbNodeConfiguration nodeConfiguration; + TbContext ctx; + TbMsgCallback callback; + + @BeforeEach + void setUp() throws TbNodeException { + deviceId = new DeviceId(UUID.randomUUID()); + callback = mock(TbMsgCallback.class); + ctx = mock(TbContext.class); + config = new TbRenameKeysNodeConfiguration().defaultConfiguration(); + config.setRenameKeysMapping(Map.of("TestKey_1", "Attribute_1", "TestKey_2", "Attribute_2")); + nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + node = spy(new TbRenameKeysNode()); + node.init(ctx, nodeConfiguration); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenDefaultConfig_whenVerify_thenOK() { + TbRenameKeysNodeConfiguration defaultConfig = new TbRenameKeysNodeConfiguration().defaultConfiguration(); + assertThat(defaultConfig.getRenameKeysMapping()).isEqualTo(Map.of("temp", "temperature")); + assertThat(defaultConfig.isFromMetadata()).isEqualTo(false); + } + + @Test + void givenMsg_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "{\"Temperature_1\":22.5,\"TestKey_2\":10.3}"; + node.onMsg(ctx, getTbMsg(deviceId, data)); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + JsonNode dataNode = JacksonUtil.toJsonNode(newMsg.getData()); + assertThat(dataNode.has("Attribute_2")).isEqualTo(true); + assertThat(dataNode.has("Temperature_1")).isEqualTo(true); + } + + @Test + void givenMetadata_whenOnMsg_thenVerifyOutput() throws Exception { + config = new TbRenameKeysNodeConfiguration().defaultConfiguration(); + config.setRenameKeysMapping(Map.of("TestKey_1", "Attribute_1", "TestKey_2", "Attribute_2")); + config.setFromMetadata(true); + nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + node.init(ctx, nodeConfiguration); + + String data = "{\"Temperature_1\":22.5,\"TestKey_2\":10.3}"; + node.onMsg(ctx, getTbMsg(deviceId, data)); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + Map mdDataMap = newMsg.getMetaData().getData(); + assertThat(mdDataMap.containsKey("Attribute_1")).isEqualTo(true); + } + + @Test + void givenEmptyKeys_whenOnMsg_thenVerifyOutput() throws Exception { + TbRenameKeysNodeConfiguration defaultConfig = new TbRenameKeysNodeConfiguration().defaultConfiguration(); + nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(defaultConfig)); + node.init(ctx, nodeConfiguration); + + String data = "{\"Temperature_1\":22.5,\"TestKey_2\":10.3}"; + TbMsg msg = getTbMsg(deviceId, data); + node.onMsg(ctx, msg); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + assertThat(newMsg.getMetaData()).isEqualTo(msg.getMetaData()); + } + + @Test + void givenMsgDataNotJSONObject_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "[]"; + TbMsg msg = getTbMsg(deviceId, data); + node.onMsg(ctx, msg); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + assertThat(newMsg).isSameAs(msg); + } + + private TbMsg getTbMsg(EntityId entityId, String data) { + final Map mdMap = Map.of( + "TestKey_1", "Test", + "country", "US", + "city", "NY" + ); + return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(mdMap), data, callback); + } +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java new file mode 100644 index 0000000000..2925ab96ae --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java @@ -0,0 +1,139 @@ +/** + * Copyright © 2016-2022 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.transform; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; + +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class TbSplitArrayMsgNodeTest { + final ObjectMapper mapper = new ObjectMapper(); + + DeviceId deviceId; + TbSplitArrayMsgNode node; + EmptyNodeConfiguration config; + TbNodeConfiguration nodeConfiguration; + TbContext ctx; + TbMsgCallback callback; + + @BeforeEach + void setUp() throws TbNodeException { + deviceId = new DeviceId(UUID.randomUUID()); + callback = mock(TbMsgCallback.class); + ctx = mock(TbContext.class); + config = new EmptyNodeConfiguration(); + nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); + node = spy(new TbSplitArrayMsgNode()); + node.init(ctx, nodeConfiguration); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenFewMsg_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "[{\"Attribute_1\":22.5,\"Attribute_2\":10.3}, {\"Attribute_1\":1,\"Attribute_2\":2}]"; + VerifyOutputMsg(data); + } + + @Test + void givenOneMsg_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "[{\"Attribute_1\":22.5,\"Attribute_2\":10.3}]"; + VerifyOutputMsg(data); + } + + @Test + void givenZeroMsg_whenOnMsg_thenVerifyOutput() throws Exception { + String data = "[]"; + VerifyOutputMsg(data); + } + + @Test + void givenNoArrayMsg_whenOnMsg_thenFailure() throws Exception { + String data = "{\"Attribute_1\":22.5,\"Attribute_2\":10.3}"; + JsonNode dataNode = JacksonUtil.toJsonNode(data); + TbMsg msg = getTbMsg(deviceId, dataNode.toString()); + node.onMsg(ctx, msg); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); + verify(ctx, never()).tellSuccess(any()); + verify(ctx, times(1)).tellFailure(newMsgCaptor.capture(), exceptionCaptor.capture()); + + assertThat(exceptionCaptor.getValue()).isInstanceOf(RuntimeException.class); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + + assertThat(newMsg).isSameAs(msg); + } + + private void VerifyOutputMsg(String data) throws Exception { + JsonNode dataNode = JacksonUtil.toJsonNode(data); + TbMsg tbMsg = getTbMsg(deviceId, dataNode.toString()); + node.onMsg(ctx, tbMsg); + + if (dataNode.size() > 1) { + ArgumentCaptor successCaptor = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor> failureCaptor = ArgumentCaptor.forClass(Consumer.class); + verify(ctx, times(dataNode.size())).enqueueForTellNext(any(), anyString(), successCaptor.capture(), failureCaptor.capture()); + for (Runnable valueCaptor : successCaptor.getAllValues()) { + valueCaptor.run(); + } + verify(ctx, times(1)).ack(tbMsg); + } else { + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(dataNode.size())).tellSuccess(newMsgCaptor.capture()); + } + verify(ctx, never()).tellFailure(any(), any()); + } + + private TbMsg getTbMsg(EntityId entityId, String data) { + Map mdMap = Map.of( + "country", "US", + "city", "NY" + ); + return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(mdMap), data, callback); + } +} diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index ffed38e79a..b1f3640585 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -97,6 +97,8 @@ transport: dtls: # Enable/disable DTLS 1.2 support enabled: "${COAP_DTLS_ENABLED:false}" + # RFC7925_RETRANSMISSION_TIMEOUT_IN_MILLISECONDS = 9000 + retransmission_timeout: "${COAP_DTLS_RETRANSMISSION_TIMEOUT_MS:9000}" # CoAP DTLS bind address bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" # CoAP DTLS bind port diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 33a8496941..fde1ea9f57 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -106,6 +106,9 @@ transport: lwm2m: # Enable/disable lvm2m transport protocol. enabled: "${LWM2M_ENABLED:true}" + dtls: + # RFC7925_RETRANSMISSION_TIMEOUT_IN_MILLISECONDS = 9000 + retransmission_timeout: "${LWM2M_DTLS_RETRANSMISSION_TIMEOUT_MS:9000}" server: id: "${LWM2M_SERVER_ID:123}" bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index 4caa27b0a2..db40fdc5d8 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -185,7 +185,8 @@ [isEditingWidget]="isEditingWidget" [isMobile]="forceDashboardMobileMode" [widgetEditMode]="widgetEditMode" - [parentDashboard]="parentDashboard"> + [parentDashboard]="parentDashboard" + [popoverComponent]="popoverComponent"> + [parentDashboard]="parentDashboard" + [popoverComponent]="popoverComponent"> diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index c145794163..14e566411f 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -17,13 +17,18 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, - Component, ElementRef, EventEmitter, HostBinding, + Component, + ElementRef, + EventEmitter, + HostBinding, Inject, Injector, Input, NgZone, OnDestroy, - OnInit, Optional, Renderer2, + OnInit, + Optional, + Renderer2, StaticProvider, ViewChild, ViewContainerRef, @@ -48,7 +53,7 @@ import { } from '@app/shared/models/dashboard.models'; import { WINDOW } from '@core/services/window.service'; import { WindowMessage } from '@shared/models/window-message.model'; -import { deepClone, guid, hashCode, isDefined, isDefinedAndNotNull, isNotEmptyStr } from '@app/core/utils'; +import { deepClone, guid, isDefined, isDefinedAndNotNull, isNotEmptyStr } from '@app/core/utils'; import { DashboardContext, DashboardPageLayout, @@ -129,7 +134,8 @@ import { MobileService } from '@core/services/mobile.service'; import { DashboardImageDialogComponent, - DashboardImageDialogData, DashboardImageDialogResult + DashboardImageDialogData, + DashboardImageDialogResult } from '@home/components/dashboard-page/dashboard-image-dialog.component'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; import cssjs from '@core/css/css'; @@ -139,6 +145,7 @@ import { MatButton } from '@angular/material/button'; import { VersionControlComponent } from '@home/components/vc/version-control.component'; import { TbPopoverService } from '@shared/components/popover.service'; import { tap } from 'rxjs/operators'; +import { TbPopoverComponent } from '@shared/components/popover.component'; // @dynamic @Component({ @@ -184,6 +191,9 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC @Input() parentDashboard?: IDashboardComponent = null; + @Input() + popoverComponent?: TbPopoverComponent = null; + @Input() parentAliasController?: IAliasController = null; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html index 4e7d11255b..0255ec8ade 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html @@ -58,6 +58,7 @@ [isRemoveActionEnabled]="isEdit && !widgetEditMode" [callbacks]="this" [ignoreLoading]="layoutCtx.ignoreLoading" - [parentDashboard]="parentDashboard"> + [parentDashboard]="parentDashboard" + [popoverComponent]="popoverComponent"> diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts index fcee0b2f0a..de3533d14e 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts @@ -33,6 +33,7 @@ import { TranslateService } from '@ngx-translate/core'; import { ItemBufferService } from '@app/core/services/item-buffer.service'; import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; import { TbCheatSheetComponent } from '@shared/components/cheatsheet.component'; +import { TbPopoverComponent } from '@shared/components/popover.component'; @Component({ selector: 'tb-dashboard-layout', @@ -81,6 +82,9 @@ export class DashboardLayoutComponent extends PageComponent implements ILayoutCo @Input() parentDashboard?: IDashboardComponent = null; + @Input() + popoverComponent?: TbPopoverComponent = null; + @ViewChild('dashboard', {static: true}) dashboard: IDashboardComponent; private rxSubscriptions = new Array(); diff --git a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts index 62598ac1dd..627294b40f 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts @@ -15,7 +15,9 @@ /// import { - AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, Component, DoCheck, Input, @@ -56,6 +58,7 @@ import { distinct } from 'rxjs/operators'; import { ResizeObserver } from '@juggle/resize-observer'; import { UtilsService } from '@core/services/utils.service'; import { WidgetComponentAction, WidgetComponentActionType } from '@home/components/widget/widget-container.component'; +import { TbPopoverComponent } from '@shared/components/popover.component'; @Component({ selector: 'tb-dashboard', @@ -136,6 +139,9 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo @Input() parentDashboard?: IDashboardComponent = null; + @Input() + popoverComponent?: TbPopoverComponent = null; + dashboardTimewindowChangedSubject: Subject = new ReplaySubject(); dashboardTimewindowChanged = this.dashboardTimewindowChangedSubject.asObservable().pipe( @@ -191,6 +197,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo ngOnInit(): void { this.dashboardWidgets.parentDashboard = this.parentDashboard; + this.dashboardWidgets.popoverComponent = this.popoverComponent; if (!this.dashboardTimewindow) { this.dashboardTimewindow = this.timeService.defaultTimewindow(); } diff --git a/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.html b/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.html index 9088f5cc33..a36cab05ff 100644 --- a/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.html @@ -79,7 +79,7 @@
datakey.delta-calculation - + , @Inject(SHARED_HOME_COMPONENTS_MODULE_TOKEN) private sharedHomeComponentsModule: Type, + @Inject(HOME_COMPONENTS_MODULE_TOKEN) private homeComponentsModule: Type, public dialog: MatDialog ) { } @@ -47,7 +48,7 @@ export class CustomDialogService { return this.dynamicComponentFactoryService.createDynamicComponentFactory( class CustomDialogComponentInstance extends CustomDialogComponent {}, template, - [this.sharedModule, CommonModule, this.sharedHomeComponentsModule]).pipe( + [this.sharedModule, CommonModule, this.sharedHomeComponentsModule, this.homeComponentsModule]).pipe( mergeMap((factory) => { const dialogData: CustomDialogContainerData = { controller, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index a7def01b1a..21aee908da 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -84,6 +84,7 @@ export enum OpenStreetMapProvider { openStreetHot = 'OpenStreetMap.HOT', esriWorldStreetMap = 'Esri.WorldStreetMap', esriWorldTopoMap = 'Esri.WorldTopoMap', + esriWorldImagery = 'Esri.WorldImagery', cartoDbPositron = 'CartoDB.Positron', cartoDbDarkMatter = 'CartoDB.DarkMatter' } @@ -94,6 +95,7 @@ export const openStreetMapProviderTranslationMap = new Map; @@ -109,6 +109,8 @@ export class DashboardWidgets implements Iterable { parentDashboard?: IDashboardComponent; + popoverComponent?: TbPopoverComponent; + [Symbol.iterator](): Iterator { return this.activeDashboardWidgets[Symbol.iterator](); } @@ -174,7 +176,7 @@ export class DashboardWidgets implements Iterable { switch (record.operation) { case 'add': this.dashboardWidgets.push( - new DashboardWidget(this.dashboard, record.widget, record.widgetLayout, this.parentDashboard) + new DashboardWidget(this.dashboard, record.widget, record.widgetLayout, this.parentDashboard, this.popoverComponent) ); break; case 'remove': @@ -190,7 +192,7 @@ export class DashboardWidgets implements Iterable { if (!isEqual(prevDashboardWidget.widget, record.widget) || !isEqual(prevDashboardWidget.widgetLayout, record.widgetLayout)) { this.dashboardWidgets[index] = new DashboardWidget(this.dashboard, record.widget, record.widgetLayout, - this.parentDashboard); + this.parentDashboard, this.popoverComponent); this.dashboardWidgets[index].highlighted = prevDashboardWidget.highlighted; this.dashboardWidgets[index].selected = prevDashboardWidget.selected; } else { @@ -345,7 +347,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { customHeaderActions: Array; widgetActions: Array; - widgetContext = new WidgetContext(this.dashboard, this, this.widget, this.parentDashboard); + widgetContext = new WidgetContext(this.dashboard, this, this.widget, this.parentDashboard, this.popoverComponent); widgetId: string; @@ -388,7 +390,8 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { private dashboard: IDashboardComponent, public widget: Widget, public widgetLayout?: WidgetLayout, - private parentDashboard?: IDashboardComponent) { + private parentDashboard?: IDashboardComponent, + private popoverComponent?: TbPopoverComponent) { if (!widget.id) { widget.id = guid(); } diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index 4686fe88e6..0bcfa8fb01 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -18,7 +18,8 @@ import { IDashboardComponent } from '@home/models/dashboard-component.models'; import { DataSet, Datasource, - DatasourceData, FormattedData, + DatasourceData, + FormattedData, JsonSettingsSchema, Widget, WidgetActionDescriptor, @@ -37,7 +38,8 @@ import { IStateController, IWidgetSubscription, IWidgetUtils, - RpcApi, StateParams, + RpcApi, + StateParams, SubscriptionEntityInfo, TimewindowFunctions, WidgetActionsApi, @@ -113,7 +115,8 @@ export class WidgetContext { constructor(public dashboard: IDashboardComponent, private dashboardWidget: IDashboardWidget, private widget: Widget, - public parentDashboard?: IDashboardComponent) {} + public parentDashboard?: IDashboardComponent, + public popoverComponent?: TbPopoverComponent) {} get stateController(): IStateController { return this.parentDashboard ? this.parentDashboard.stateController : this.dashboard.stateController; diff --git a/ui-ngx/src/app/shared/components/popover.component.ts b/ui-ngx/src/app/shared/components/popover.component.ts index 99321974af..20815fd5fb 100644 --- a/ui-ngx/src/app/shared/components/popover.component.ts +++ b/ui-ngx/src/app/shared/components/popover.component.ts @@ -57,6 +57,7 @@ import { } from '@shared/components/popover.models'; import { distinctUntilChanged, take, takeUntil } from 'rxjs/operators'; import { isNotEmptyStr, onParentScrollOrWindowResize } from '@core/utils'; +import { animate, AnimationBuilder, AnimationMetadata, style } from '@angular/animations'; export type TbPopoverTrigger = 'click' | 'focus' | 'hover' | null; @@ -304,6 +305,7 @@ export class TbPopoverDirective implements OnChanges, OnDestroy, AfterViewInit {
; + @ViewChild('popover', { static: false }) popover!: ElementRef; tbContent: string | TemplateRef | null = null; tbComponentFactory: ComponentFactory | null = null; @@ -442,6 +445,7 @@ export class TbPopoverComponent implements OnDestroy, OnInit { constructor( public cdr: ChangeDetectorRef, private renderer: Renderer2, + private animationBuilder: AnimationBuilder, @Optional() private directionality: Directionality ) {} @@ -532,6 +536,35 @@ export class TbPopoverComponent implements OnDestroy, OnInit { }); } + resize(width: string, height: string, animationDurationMs?: number) { + if (animationDurationMs && animationDurationMs > 0) { + const prevWidth = this.popover.nativeElement.offsetWidth; + const prevHeight = this.popover.nativeElement.offsetHeight; + const animationMetadata: AnimationMetadata[] = [style({width: prevWidth + 'px', height: prevHeight + 'px'}), + animate(animationDurationMs + 'ms', style({width, height}))]; + const factory = this.animationBuilder.build(animationMetadata); + const player = factory.create(this.popover.nativeElement); + player.play(); + const resize$ = new ResizeObserver(() => { + this.updatePosition(); + }); + resize$.observe(this.popover.nativeElement); + player.onDone(() => { + player.destroy(); + resize$.disconnect(); + this.setSize(width, height); + }); + } else { + this.setSize(width, height); + } + } + + private setSize(width: string, height: string) { + this.renderer.setStyle(this.popover.nativeElement, 'width', width); + this.renderer.setStyle(this.popover.nativeElement, 'height', height); + this.updatePosition(); + } + updatePosition(): void { if (this.origin && this.overlay && this.overlay.overlayRef) { this.overlay.overlayRef.updatePosition(); diff --git a/ui-ngx/src/app/shared/components/popover.service.ts b/ui-ngx/src/app/shared/components/popover.service.ts index 713e8d337b..3f05ed02a6 100644 --- a/ui-ngx/src/app/shared/components/popover.service.ts +++ b/ui-ngx/src/app/shared/components/popover.service.ts @@ -16,8 +16,12 @@ import { ComponentFactory, - ComponentFactoryResolver, ElementRef, Inject, - Injectable, Injector, + ComponentFactoryResolver, + ComponentRef, + ElementRef, + Inject, + Injectable, + Injector, Renderer2, Type, ViewContainerRef @@ -53,11 +57,23 @@ export class TbPopoverService { } } + createPopoverRef(hostView: ViewContainerRef): ComponentRef { + return hostView.createComponent(this.componentFactory); + } + displayPopover(trigger: Element, renderer: Renderer2, hostView: ViewContainerRef, componentType: Type, preferredPlacement: PopoverPlacement = 'top', hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, popoverStyle: any = {}, style?: any, showCloseButton = true): TbPopoverComponent { - const componentRef = hostView.createComponent(this.componentFactory); + const componentRef = this.createPopoverRef(hostView); + return this.displayPopoverWithComponentRef(componentRef, trigger, renderer, componentType, preferredPlacement, hideOnClickOutside, + injector, context, overlayStyle, popoverStyle, style, showCloseButton); + } + + displayPopoverWithComponentRef(componentRef: ComponentRef, trigger: Element, renderer: Renderer2, + componentType: Type, preferredPlacement: PopoverPlacement = 'top', + hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, + popoverStyle: any = {}, style?: any, showCloseButton = true): TbPopoverComponent { const component = componentRef.instance; this.popoverWithTriggers.push({ trigger, diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index bf5cac3c73..6d2a098ca6 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -127,6 +127,7 @@ export const HelpLinks = { ruleNodeRestApiCall: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node', ruleNodeSendEmail: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-email-node', ruleNodeSendSms: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-sms-node', + ruleNodeMath: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#math-function-node', tenants: helpBaseUrl + '/docs/user-guide/ui/tenants', tenantProfiles: helpBaseUrl + '/docs/user-guide/ui/tenant-profiles', customers: helpBaseUrl + '/docs/user-guide/ui/customers', diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index c6549f5b39..df8ea3ed87 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -461,6 +461,7 @@ const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.edge.TbMsgPushToEdgeNode': 'ruleNodePushToEdge', 'org.thingsboard.rule.engine.flow.TbRuleChainInputNode': 'ruleNodeRuleChain', 'org.thingsboard.rule.engine.flow.TbRuleChainOutputNode': 'ruleNodeOutputNode', + 'org.thingsboard.rule.engine.math.TbMathNode': 'ruleNodeMath', }; export function getRuleNodeHelpLink(component: RuleNodeComponentDescriptor): string { diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 8cb71e0d9d..bd070f0b75 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -26,6 +26,7 @@ import Flow from '@flowjs/flow.js'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButtonModule } from '@angular/material/button'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatCardModule } from '@angular/material/card'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatChipsModule } from '@angular/material/chips'; @@ -299,6 +300,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) RouterModule, TranslateModule, MatButtonModule, + MatButtonToggleModule, MatCheckboxModule, MatIconModule, MatCardModule, @@ -410,6 +412,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) WidgetsBundleSelectComponent, ValueInputComponent, MatButtonModule, + MatButtonToggleModule, MatCheckboxModule, MatIconModule, MatCardModule, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 061f042e44..434535a785 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4444,6 +4444,7 @@ "openstreet-provider-hot": "OpenStreetMap.HOT", "openstreet-provider-esri-street": "Esri.WorldStreetMap", "openstreet-provider-esri-topo": "Esri.WorldTopoMap", + "openstreet-provider-esri-imagery": "Esri.WorldImagery", "openstreet-provider-cartodb-positron": "CartoDB.Positron", "openstreet-provider-cartodb-dark-matter": "CartoDB.DarkMatter", "use-custom-provider": "Use custom provider",