From f8bb2839aa5399d7db91ac4249050c70ee5614ea Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 15 Oct 2019 17:11:59 +0300 Subject: [PATCH 01/46] Add support import label --- ui/src/app/api/entity.service.js | 3 ++- ui/src/app/common/types.constant.js | 4 ++++ ui/src/app/import-export/import-dialog-csv.controller.js | 6 +++++- .../app/import-export/table-columns-assignment.directive.js | 6 ++++++ ui/src/app/import-export/table-columns-assignment.tpl.html | 1 + ui/src/app/locale/locale.constant-en_US.json | 1 + ui/src/app/locale/locale.constant-ru_RU.json | 1 + ui/src/app/locale/locale.constant-uk_UA.json | 1 + 8 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index f39615c933..f474ff4f42 100644 --- a/ui/src/app/api/entity.service.js +++ b/ui/src/app/api/entity.service.js @@ -1130,7 +1130,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device let statisticalInfo = {}; let newEntity = { name: entityParameters.name, - type: entityParameters.type + type: entityParameters.type, + label: entityParameters.label }; let promise; switch (entityType) { diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index 37ccd91302..e6e65bbecf 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -369,6 +369,10 @@ export default angular.module('thingsboard.types', []) name: 'import.column-type.type', value: 'type' }, + label: { + name: 'import.column-type.label', + value: 'label' + }, clientAttribute: { name: 'import.column-type.client-attribute', value: 'CLIENT_ATTRIBUTE' diff --git a/ui/src/app/import-export/import-dialog-csv.controller.js b/ui/src/app/import-export/import-dialog-csv.controller.js index a7b5329205..e11f59c5b4 100644 --- a/ui/src/app/import-export/import-dialog-csv.controller.js +++ b/ui/src/app/import-export/import-dialog-csv.controller.js @@ -98,7 +98,7 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo vm.columnsParam = []; var columnParam = {}; for (var i = 0; i < parseData.headers.length; i++) { - if (vm.importParameters.isHeader && parseData.headers[i].search(/^(name|type)$/im) === 0) { + if (vm.importParameters.isHeader && parseData.headers[i].search(/^(name|type|label)$/im) === 0) { columnParam = { type: types.importEntityColumnType[parseData.headers[i].toLowerCase()].value, key: parseData.headers[i].toLowerCase(), @@ -126,6 +126,7 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo var entityData = { name: "", type: "", + label: "", accessToken: "", attributes: { server: [], @@ -162,6 +163,9 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo case types.importEntityColumnType.type.value: entityData.type = importData.rows[i][j]; break; + case types.importEntityColumnType.label.value: + entityData.label = importData.rows[i][j]; + break; } } entitiesData.push(entityData); diff --git a/ui/src/app/import-export/table-columns-assignment.directive.js b/ui/src/app/import-export/table-columns-assignment.directive.js index a645e07392..5d96ba1c83 100644 --- a/ui/src/app/import-export/table-columns-assignment.directive.js +++ b/ui/src/app/import-export/table-columns-assignment.directive.js @@ -44,6 +44,7 @@ function TableColumnsAssignmentController($scope, types, $timeout) { vm.columnTypes.name = types.importEntityColumnType.name; vm.columnTypes.type = types.importEntityColumnType.type; + vm.columnTypes.label = types.importEntityColumnType.label; switch (vm.entityType) { case types.entityType.device: @@ -62,6 +63,7 @@ function TableColumnsAssignmentController($scope, types, $timeout) { if (newVal) { var isSelectName = false; var isSelectType = false; + var isSelectLabel = false; var isSelectCredentials = false; for (var i = 0; i < newVal.length; i++) { switch (newVal[i].type) { @@ -71,6 +73,9 @@ function TableColumnsAssignmentController($scope, types, $timeout) { case types.importEntityColumnType.type.value: isSelectType = true; break; + case types.importEntityColumnType.label.value: + isSelectLabel = true; + break; case types.importEntityColumnType.accessToken.value: isSelectCredentials = true; break; @@ -84,6 +89,7 @@ function TableColumnsAssignmentController($scope, types, $timeout) { $timeout(function () { vm.columnTypes.name.disable = isSelectName; vm.columnTypes.type.disable = isSelectType; + vm.columnTypes.label.disable = isSelectLabel; if (angular.isDefined(vm.columnTypes.accessToken)) { vm.columnTypes.accessToken.disable = isSelectCredentials; } diff --git a/ui/src/app/import-export/table-columns-assignment.tpl.html b/ui/src/app/import-export/table-columns-assignment.tpl.html index f00a08251c..b1eeafb8a7 100644 --- a/ui/src/app/import-export/table-columns-assignment.tpl.html +++ b/ui/src/app/import-export/table-columns-assignment.tpl.html @@ -41,6 +41,7 @@ Date: Sun, 8 Dec 2019 23:52:29 +0200 Subject: [PATCH 02/46] init commit --- .../CassandraDatabaseUpgradeService.java | 7 ++++ .../install/SqlDatabaseUpgradeService.java | 3 ++ .../server/common/data/alarm/Alarm.java | 4 +++ .../server/dao/alarm/BaseAlarmService.java | 33 ++++++++++++++++--- .../server/dao/model/ModelConstants.java | 1 + .../server/dao/model/nosql/AlarmEntity.java | 20 +++++++++++ .../server/dao/model/sql/AlarmEntity.java | 17 ++++++++++ .../resources/cassandra/schema-entities.cql | 1 + .../main/resources/sql/schema-entities.sql | 1 + .../rule/engine/action/TbCreateAlarmNode.java | 25 ++++++++++++-- .../TbCreateAlarmNodeConfiguration.java | 8 ++++- 11 files changed, 113 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java index 68ca728823..4732ef6be7 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java @@ -270,9 +270,16 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { case "2.4.1": log.info("Updating schema ..."); String updateAssetTableStmt = "alter table asset add label text"; + String updateAlarmTableStmt = "alter table alarm add propagate_relation_types text"; try { + log.info("Updating assets ..."); cluster.getSession().execute(updateAssetTableStmt); Thread.sleep(2500); + log.info("Assets updated."); + log.info("Updating alarms ..."); + cluster.getSession().execute(updateAlarmTableStmt); + Thread.sleep(2500); + log.info("Alarms updated."); } catch (InvalidQueryException e) {} log.info("Schema updated."); break; 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 3210742388..1ded097e52 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 @@ -193,6 +193,9 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { try { conn.createStatement().execute("ALTER TABLE asset ADD CONSTRAINT asset_name_unq_key UNIQUE (tenant_id, name)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script } catch (Exception e) {} + try { + conn.createStatement().execute("ALTER TABLE alarm ADD COLUMN propagate_relation_types varchar"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script + } catch (Exception e) {} log.info("Schema updated."); } break; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java index 065321ff91..b96f86b715 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java @@ -26,6 +26,8 @@ import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import java.util.List; + /** * Created by ashvayka on 11.05.17. */ @@ -45,6 +47,7 @@ public class Alarm extends BaseData implements HasName, HasTenantId { private long clearTs; private transient JsonNode details; private boolean propagate; + private List propagateRelationTypes; public Alarm() { super(); @@ -68,6 +71,7 @@ public class Alarm extends BaseData implements HasName, HasTenantId { this.clearTs = alarm.getClearTs(); this.details = alarm.getDetails(); this.propagate = alarm.isPropagate(); + this.propagateRelationTypes = alarm.getPropagateRelationTypes(); } @Override 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 8a4279fe7f..fa5ce6d4b4 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 @@ -23,8 +23,8 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmId; @@ -52,6 +52,7 @@ import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; @@ -59,6 +60,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -154,8 +156,16 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private List getParentEntities(Alarm alarm) throws InterruptedException, ExecutionException { EntityRelationsQuery query = new EntityRelationsQuery(); - query.setParameters(new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE, false)); - return relationService.findByQuery(alarm.getTenantId(), query).get().stream().map(EntityRelation::getFrom).collect(Collectors.toList()); + RelationsSearchParameters parameters = new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE, false); + query.setParameters(parameters); + List propagateRelationTypes = alarm.getPropagateRelationTypes(); + if (!CollectionUtils.isEmpty(propagateRelationTypes)) { + return relationService.findByQuery(alarm.getTenantId(), query).get().stream() + .filter(entityRelation -> propagateRelationTypes.contains(entityRelation.getType())) + .map(EntityRelation::getFrom).collect(Collectors.toList()); + } else { + return relationService.findByQuery(alarm.getTenantId(), query).get().stream().map(EntityRelation::getFrom).collect(Collectors.toList()); + } } private ListenableFuture updateAlarm(Alarm update) { @@ -360,13 +370,28 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ existing.setSeverity(alarm.getSeverity()); existing.setDetails(alarm.getDetails()); existing.setPropagate(existing.isPropagate() || alarm.isPropagate()); + List existingPropagateRelationTypes = existing.getPropagateRelationTypes(); + List newRelationTypes = alarm.getPropagateRelationTypes(); + if (!CollectionUtils.isEmpty(existingPropagateRelationTypes) && !CollectionUtils.isEmpty(newRelationTypes)) { + existing.setPropagateRelationTypes(Stream.concat(existingPropagateRelationTypes.stream(), newRelationTypes.stream()) + .distinct() + .collect(Collectors.toList())); + } else { + existing.setPropagateRelationTypes(Collections.emptyList()); + } return existing; } private void updateRelations(Alarm alarm, AlarmStatus oldStatus, AlarmStatus newStatus) { try { List relations = relationService.findByToAsync(alarm.getTenantId(), alarm.getId(), RelationTypeGroup.ALARM).get(); - Set parents = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet()); + Set parents; + List propagateRelationTypes = alarm.getPropagateRelationTypes(); + if (!CollectionUtils.isEmpty(propagateRelationTypes)) { + parents = relations.stream().filter(entityRelation -> propagateRelationTypes.contains(entityRelation.getType())).map(EntityRelation::getFrom).collect(Collectors.toSet()); + } else { + parents = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet()); + } for (EntityId parentId : parents) { updateAlarmRelation(alarm.getTenantId(), parentId, alarm.getId(), oldStatus, newStatus); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index c466c034fc..4605b405ca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -231,6 +231,7 @@ public class ModelConstants { public static final String ALARM_ACK_TS_PROPERTY = "ack_ts"; public static final String ALARM_CLEAR_TS_PROPERTY = "clear_ts"; public static final String ALARM_PROPAGATE_PROPERTY = "propagate"; + public static final String ALARM_PROPAGATE_RELATION_TYPES = "propagate_relation_types"; public static final String ALARM_BY_ID_VIEW_NAME = "alarm_by_id"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AlarmEntity.java index 807a73fe38..e274ca3348 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AlarmEntity.java @@ -23,6 +23,8 @@ import com.datastax.driver.mapping.annotations.Table; import com.fasterxml.jackson.databind.JsonNode; import lombok.EqualsAndHashCode; import lombok.ToString; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmId; @@ -36,6 +38,7 @@ import org.thingsboard.server.dao.model.type.AlarmStatusCodec; import org.thingsboard.server.dao.model.type.EntityTypeCodec; import org.thingsboard.server.dao.model.type.JsonCodec; +import java.util.Arrays; import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ACK_TS_PROPERTY; @@ -46,6 +49,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.ALARM_END_TS_PROPE import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_PROPAGATE_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_PROPAGATE_RELATION_TYPES; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_SEVERITY_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_START_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_STATUS_PROPERTY; @@ -102,6 +106,9 @@ public final class AlarmEntity implements BaseEntity { @Column(name = ALARM_PROPAGATE_PROPERTY) private Boolean propagate; + @Column(name = ALARM_PROPAGATE_RELATION_TYPES) + private String propagateRelationTypes; + public AlarmEntity() { super(); } @@ -125,6 +132,12 @@ public final class AlarmEntity implements BaseEntity { this.ackTs = alarm.getAckTs(); this.clearTs = alarm.getClearTs(); this.details = alarm.getDetails(); + this.details = alarm.getDetails(); + if (!CollectionUtils.isEmpty(alarm.getPropagateRelationTypes())) { + this.propagateRelationTypes = String.join(",", alarm.getPropagateRelationTypes()); + } else { + this.propagateRelationTypes = null; + } } public UUID getId() { @@ -231,6 +244,10 @@ public final class AlarmEntity implements BaseEntity { this.propagate = propagate; } + public String getPropagateRelationTypes() { return propagateRelationTypes; } + + public void setPropagateRelationTypes(String propagateRelationTypes) { this.propagateRelationTypes = propagateRelationTypes; } + @Override public Alarm toData() { Alarm alarm = new Alarm(new AlarmId(id)); @@ -248,6 +265,9 @@ public final class AlarmEntity implements BaseEntity { alarm.setAckTs(ackTs); alarm.setClearTs(clearTs); alarm.setDetails(details); + if(!StringUtils.isEmpty(propagateRelationTypes)) { + alarm.setPropagateRelationTypes(Arrays.asList(propagateRelationTypes.split(","))); + } return alarm; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java index f6cfb7189c..03b6218be9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java @@ -21,6 +21,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.UUIDConverter; import org.thingsboard.server.common.data.alarm.Alarm; @@ -40,6 +42,8 @@ import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.Table; +import java.util.Arrays; + import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ACK_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_CLEAR_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COLUMN_FAMILY_NAME; @@ -47,6 +51,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.ALARM_END_TS_PROPE import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_PROPAGATE_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_PROPAGATE_RELATION_TYPES; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_SEVERITY_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_START_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_STATUS_PROPERTY; @@ -99,6 +104,9 @@ public final class AlarmEntity extends BaseSqlEntity implements BaseEntit @Column(name = ALARM_PROPAGATE_PROPERTY) private Boolean propagate; + @Column(name = ALARM_PROPAGATE_RELATION_TYPES) + private String propagateRelationTypes; + public AlarmEntity() { super(); } @@ -122,6 +130,12 @@ public final class AlarmEntity extends BaseSqlEntity implements BaseEntit this.ackTs = alarm.getAckTs(); this.clearTs = alarm.getClearTs(); this.details = alarm.getDetails(); + if (!CollectionUtils.isEmpty(alarm.getPropagateRelationTypes())) { + this.propagateRelationTypes = String.join(",", alarm.getPropagateRelationTypes()); + } else { + this.propagateRelationTypes = null; + } + } @Override @@ -141,6 +155,9 @@ public final class AlarmEntity extends BaseSqlEntity implements BaseEntit alarm.setAckTs(ackTs); alarm.setClearTs(clearTs); alarm.setDetails(details); + if(!StringUtils.isEmpty(propagateRelationTypes)) { + alarm.setPropagateRelationTypes(Arrays.asList(propagateRelationTypes.split(","))); + } return alarm; } diff --git a/dao/src/main/resources/cassandra/schema-entities.cql b/dao/src/main/resources/cassandra/schema-entities.cql index a07e27cbe1..5a07c4f2ad 100644 --- a/dao/src/main/resources/cassandra/schema-entities.cql +++ b/dao/src/main/resources/cassandra/schema-entities.cql @@ -306,6 +306,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.alarm ( clear_ts bigint, details text, propagate boolean, + propagate_relation_types text, PRIMARY KEY ((tenant_id, originator_id, originator_type), type, id) ) WITH CLUSTERING ORDER BY ( type ASC, id DESC); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 4b21d851a5..087240ec33 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -34,6 +34,7 @@ CREATE TABLE IF NOT EXISTS alarm ( start_ts bigint, status varchar(255), tenant_id varchar(31), + propagate_relation_types varchar, type varchar(255) ); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java index d6f6236311..e17b65be72 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java @@ -21,11 +21,11 @@ import com.google.common.base.Function; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.RuleNode; 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.api.util.TbNodeUtils; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.TenantId; @@ -33,6 +33,8 @@ import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import java.io.IOException; +import java.util.Collections; +import java.util.List; @Slf4j @RuleNode( @@ -56,7 +58,11 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode relationTypes = this.config.getRelationTypes(); + if (relationTypes == null) { + relationTypes = Collections.emptyList(); + } return Alarm.builder() .tenantId(tenantId) .originator(msg.getOriginator()) @@ -145,6 +165,7 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode { @@ -26,18 +29,21 @@ public class TbCreateAlarmNodeConfiguration extends TbAbstractAlarmNodeConfigura private boolean propagate; private boolean useMessageAlarmData; + private List relationTypes; + @Override public TbCreateAlarmNodeConfiguration defaultConfiguration() { TbCreateAlarmNodeConfiguration configuration = new TbCreateAlarmNodeConfiguration(); configuration.setAlarmDetailsBuildJs("var details = {};\n" + "if (metadata.prevAlarmDetails) {\n" + " details = JSON.parse(metadata.prevAlarmDetails);\n" + - "}\n"+ + "}\n" + "return details;"); configuration.setAlarmType("General Alarm"); configuration.setSeverity(AlarmSeverity.CRITICAL); configuration.setPropagate(false); configuration.setUseMessageAlarmData(false); + configuration.setRelationTypes(Collections.emptyList()); return configuration; } } From f9c65d709db9cfcaef40ffa8b3a8dbb6a394ff76 Mon Sep 17 00:00:00 2001 From: Dmytro Shvaika Date: Mon, 9 Dec 2019 15:57:26 +0200 Subject: [PATCH 03/46] code update --- .../server/dao/alarm/BaseAlarmService.java | 14 +++++++------ .../rule/engine/action/TbCreateAlarmNode.java | 20 +++---------------- 2 files changed, 11 insertions(+), 23 deletions(-) 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 fa5ce6d4b4..6d3af6c118 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 @@ -372,12 +372,14 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ existing.setPropagate(existing.isPropagate() || alarm.isPropagate()); List existingPropagateRelationTypes = existing.getPropagateRelationTypes(); List newRelationTypes = alarm.getPropagateRelationTypes(); - if (!CollectionUtils.isEmpty(existingPropagateRelationTypes) && !CollectionUtils.isEmpty(newRelationTypes)) { - existing.setPropagateRelationTypes(Stream.concat(existingPropagateRelationTypes.stream(), newRelationTypes.stream()) - .distinct() - .collect(Collectors.toList())); - } else { - existing.setPropagateRelationTypes(Collections.emptyList()); + if (!CollectionUtils.isEmpty(newRelationTypes)) { + if(!CollectionUtils.isEmpty(existingPropagateRelationTypes)) { + existing.setPropagateRelationTypes(Stream.concat(existingPropagateRelationTypes.stream(), newRelationTypes.stream()) + .distinct() + .collect(Collectors.toList())); + } else { + existing.setPropagateRelationTypes(newRelationTypes); + } } return existing; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java index e17b65be72..06352d9241 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java @@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import java.io.IOException; -import java.util.Collections; import java.util.List; @Slf4j @@ -55,13 +54,12 @@ import java.util.List; public class TbCreateAlarmNode extends TbAbstractAlarmNode { private static ObjectMapper mapper = new ObjectMapper(); + private List relationTypes; @Override protected TbCreateAlarmNodeConfiguration loadAlarmNodeConfig(TbNodeConfiguration configuration) throws TbNodeException { TbCreateAlarmNodeConfiguration nodeConfiguration = TbNodeUtils.convert(configuration, TbCreateAlarmNodeConfiguration.class); - if(nodeConfiguration.getRelationTypes() == null) { - nodeConfiguration.setRelationTypes(Collections.emptyList()); - } + relationTypes = nodeConfiguration.getRelationTypes(); return nodeConfiguration; } @@ -72,7 +70,6 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode relationTypes = this.config.getRelationTypes(); - if (relationTypes == null) { - relationTypes = Collections.emptyList(); - } return Alarm.builder() .tenantId(tenantId) .originator(msg.getOriginator()) From c84a8a5e672b3934a30499b1baf3363b80f9a476 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 10 Dec 2019 15:25:03 +0200 Subject: [PATCH 04/46] Version set to 2.5.0-SNAPSHOT --- application/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- common/util/pom.xml | 2 +- dao/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/package.json | 2 +- msa/js-executor/pom.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/web-ui/package.json | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 ++-- pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- tools/pom.xml | 2 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- ui/package.json | 2 +- ui/pom.xml | 2 +- 37 files changed, 38 insertions(+), 38 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 68ae1aa77c..06e2437417 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT thingsboard application diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index b2a8cd467e..8509364af2 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index 155a00b7f9..e88efd9cd5 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index 60702c0801..ad7c8146df 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index ce20b753ba..a748481f9d 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 7821051137..36f2597a8e 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index 26d478b596..30f2f1b66c 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 644df5a7b4..a0c25da472 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index ef0ae8eabd..09a517a666 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index ca36845902..405b75f175 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index 88bc2f64d8..dc6cbfd1ba 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index c695ac573e..a126dbb451 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 5e527a5aad..5ad7de4978 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index a6b5d65ff7..fac58891d8 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index da4eb09b09..0cdafffef1 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "2.4.2", + "version": "2.5.0", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 27636dbecd..3bfd3acfbb 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index 84d00e2d88..f9345f9419 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index 8a2bab084a..820779b03e 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index f653fb7cab..ac9da0cca2 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index b606ba29fd..1b23d84b5a 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index c38756d5cd..b36ef5c0cf 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 7402d2e209..bb95512b1a 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index f869e02f18..84777e05c8 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index ce82272a26..176791d65a 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "2.4.2", + "version": "2.5.0", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index c7bcf39caf..12d3040651 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 869eb2abb0..ef9e905839 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,12 +19,12 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT thingsboard org.thingsboard netty-mqtt - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 80038123ff..898c417300 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT pom Thingsboard diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 4197f275b6..0ceb8ed0d8 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 7253dcf483..312c1b2766 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 627aa42ab3..62901d4e18 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index b192c1bf38..6a9644d003 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 08629c2a5e..2ae71754d6 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 8722273815..6686bbc659 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index badb11f6cd..e5b7250888 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index c830bbc009..5cf5d295af 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT thingsboard transport diff --git a/ui/package.json b/ui/package.json index bb7c1b4979..4c67341178 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard", "private": true, - "version": "2.4.2", + "version": "2.5.0", "description": "ThingsBoard UI", "licenses": [ { diff --git a/ui/pom.xml b/ui/pom.xml index f037ccfde6..75bed7519d 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT thingsboard org.thingsboard From 88434dec27a5c318701fdbce4d17af4b7e041a19 Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Wed, 11 Dec 2019 13:57:39 +0200 Subject: [PATCH 05/46] Improvement alarms widget limit (#2257) * Add support import label * Add chunk size * Refactoring and add template to max limit * Add max number load alarms --- ui/src/app/api/alarm.service.js | 37 +++++++-- ui/src/app/api/subscription.js | 6 ++ .../widget/widget-config.directive.js | 8 +- .../components/widget/widget-config.tpl.html | 75 +++++++++++++------ .../components/widget/widget.controller.js | 4 + ui/src/app/locale/locale.constant-en_US.json | 8 +- ui/src/app/locale/locale.constant-ru_RU.json | 8 +- ui/src/app/locale/locale.constant-uk_UA.json | 10 ++- 8 files changed, 120 insertions(+), 36 deletions(-) diff --git a/ui/src/app/api/alarm.service.js b/ui/src/app/api/alarm.service.js index 03269fe333..f1b0513ec6 100644 --- a/ui/src/app/api/alarm.service.js +++ b/ui/src/app/api/alarm.service.js @@ -183,7 +183,7 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { return deferred.promise; } - function fetchAlarms(alarmsQuery, pageLink, deferred, alarmsList) { + function fetchAlarms(alarmsQuery, pageLink, deferred, leftToLoad, alarmsList) { getAlarms(alarmsQuery.entityType, alarmsQuery.entityId, pageLink, alarmsQuery.alarmSearchStatus, alarmsQuery.alarmStatus, alarmsQuery.fetchOriginator, false, {ignoreLoading: true}).then( @@ -192,8 +192,19 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { alarmsList = []; } alarmsList = alarmsList.concat(alarms.data); + if (angular.isDefined(leftToLoad)) { + leftToLoad -= pageLink.limit; + if (leftToLoad === 0) { + alarmsList = $filter('orderBy')(alarmsList, ['-createdTime']); + deferred.resolve(alarmsList); + return; + } + if (leftToLoad < pageLink.limit) { + alarms.nextPageLink.limit = leftToLoad; + } + } if (alarms.hasNext && !alarmsQuery.limit) { - fetchAlarms(alarmsQuery, alarms.nextPageLink, deferred, alarmsList); + fetchAlarms(alarmsQuery, alarms.nextPageLink, deferred, leftToLoad, alarmsList); } else { alarmsList = $filter('orderBy')(alarmsList, ['-createdTime']); deferred.resolve(alarmsList); @@ -209,26 +220,34 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { var deferred = $q.defer(); var time = Date.now(); var pageLink; + var leftToLoad; if (alarmsQuery.limit) { pageLink = { limit: alarmsQuery.limit }; } else if (alarmsQuery.interval) { pageLink = { - limit: 100, + limit: alarmsQuery.alarmsFetchSize || 100, startTime: time - alarmsQuery.interval }; } else if (alarmsQuery.startTime) { pageLink = { - limit: 100, + limit: alarmsQuery.alarmsFetchSize || 100, startTime: Math.round(alarmsQuery.startTime) - } + }; if (alarmsQuery.endTime) { pageLink.endTime = Math.round(alarmsQuery.endTime); } } - fetchAlarms(alarmsQuery, pageLink, deferred); + if (angular.isDefined(alarmsQuery.alarmsMaxCountLoad) && alarmsQuery.alarmsMaxCountLoad !== 0) { + leftToLoad = alarmsQuery.alarmsMaxCountLoad; + if (leftToLoad < pageLink.limit) { + pageLink.limit = leftToLoad; + } + } + + fetchAlarms(alarmsQuery, pageLink, deferred, leftToLoad); return deferred.promise; } @@ -276,8 +295,10 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { entityType: alarmSource.entityType, entityId: alarmSource.entityId, alarmSearchStatus: alarmSourceListener.alarmSearchStatus, - alarmStatus: null - } + alarmStatus: null, + alarmsMaxCountLoad: alarmSourceListener.alarmsMaxCountLoad, + alarmsFetchSize: alarmSourceListener.alarmsFetchSize + }; var originatorKeys = $filter('filter')(alarmSource.dataKeys, {name: 'originator'}); if (originatorKeys && originatorKeys.length) { alarmSourceListener.alarmsQuery.fetchOriginator = true; diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js index 728af2d38f..89f8aae309 100644 --- a/ui/src/app/api/subscription.js +++ b/ui/src/app/api/subscription.js @@ -75,6 +75,10 @@ export default class Subscription { options.alarmSearchStatus : this.ctx.types.alarmSearchStatus.any; this.alarmsPollingInterval = angular.isDefined(options.alarmsPollingInterval) ? options.alarmsPollingInterval : 5000; + this.alarmsMaxCountLoad = angular.isDefined(options.alarmsMaxCountLoad) ? + options.alarmsMaxCountLoad : 0; + this.alarmsFetchSize = angular.isDefined(options.alarmsFetchSize) ? + options.alarmsFetchSize : 100; this.alarmSourceListener = null; this.alarms = []; @@ -915,6 +919,8 @@ export default class Subscription { alarmSource: this.alarmSource, alarmSearchStatus: this.alarmSearchStatus, alarmsPollingInterval: this.alarmsPollingInterval, + alarmsMaxCountLoad: this.alarmsMaxCountLoad, + alarmsFetchSize: this.alarmsFetchSize, alarmsUpdated: function(alarms, apply) { subscription.alarmsUpdated(alarms, apply); } diff --git a/ui/src/app/components/widget/widget-config.directive.js b/ui/src/app/components/widget/widget-config.directive.js index 5c0b704eb1..470726a835 100644 --- a/ui/src/app/components/widget/widget-config.directive.js +++ b/ui/src/app/components/widget/widget-config.directive.js @@ -173,6 +173,10 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout config.alarmSearchStatus : types.alarmSearchStatus.any; scope.alarmsPollingInterval = angular.isDefined(config.alarmsPollingInterval) ? config.alarmsPollingInterval : 5; + scope.alarmsMaxCountLoad = angular.isDefined(config.alarmsMaxCountLoad) ? + config.alarmsMaxCountLoad : 0; + scope.alarmsFetchSize = angular.isDefined(config.alarmsFetchSize) ? + config.alarmsFetchSize : 100; if (config.alarmSource) { scope.alarmSource.value = config.alarmSource; } else { @@ -243,7 +247,7 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout scope.$watch('title + showTitleIcon + titleIcon + iconColor + iconSize + titleTooltip + showTitle + dropShadow + enableFullscreen + backgroundColor + ' + 'color + padding + margin + widgetStyle + titleStyle + mobileOrder + mobileHeight + units + decimals + useDashboardTimewindow + ' + - 'displayTimewindow + alarmSearchStatus + alarmsPollingInterval + showLegend', function () { + 'displayTimewindow + alarmSearchStatus + alarmsPollingInterval + alarmsMaxCountLoad + alarmsFetchSize + showLegend', function () { if (ngModelCtrl.$viewValue) { var value = ngModelCtrl.$viewValue; if (value.config) { @@ -277,6 +281,8 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout config.displayTimewindow = scope.displayTimewindow; config.alarmSearchStatus = scope.alarmSearchStatus; config.alarmsPollingInterval = scope.alarmsPollingInterval; + config.alarmsMaxCountLoad = scope.alarmsMaxCountLoad; + config.alarmsFetchSize = scope.alarmsFetchSize; config.showLegend = scope.showLegend; } if (value.layout) { diff --git a/ui/src/app/components/widget/widget-config.tpl.html b/ui/src/app/components/widget/widget-config.tpl.html index e5ac7b62b2..c5f6c298c7 100644 --- a/ui/src/app/components/widget/widget-config.tpl.html +++ b/ui/src/app/components/widget/widget-config.tpl.html @@ -37,29 +37,58 @@ is-edit="true" flex ng-model="timewindow"> -
- - - - - {{ ('alarm.search-status.' + searchStatus) | translate }} - - - - - - -
-
alarm.polling-interval-required
-
alarm.min-polling-interval-message
-
-
+
+
+ + + + + {{ ('alarm.search-status.' + searchStatus) | translate }} + + + + + + +
+
alarm.polling-interval-required
+
alarm.min-polling-interval-message
+
+
+
+
+ + + +
+
alarm.max-count-load-required
+
alarm.max-count-load-error-min
+
+
+ + + +
+
alarm.fetch-size-required
+
alarm.fetch-size-error-min
+
+
+
Date: Wed, 11 Dec 2019 14:27:13 +0200 Subject: [PATCH 06/46] Async JS Execution --- .../script/RuleNodeJsScriptEngine.java | 5 +++ .../rule/engine/api/ScriptEngine.java | 2 + .../engine/action/TbAbstractAlarmNode.java | 15 ++++++-- .../rule/engine/action/TbAlarmNodeTest.java | 38 +++---------------- 4 files changed, 24 insertions(+), 36 deletions(-) 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 12150b806a..8b08333d3b 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 @@ -139,6 +139,11 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S return executeScript(msg); } + @Override + public ListenableFuture executeJsonAsync(TbMsg msg) throws ScriptException { + return executeScriptAsync(msg); + } + @Override public String executeToString(TbMsg msg) throws ScriptException { JsonNode result = executeScript(msg); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ScriptEngine.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ScriptEngine.java index f72adf04ab..1ffaabd6d1 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ScriptEngine.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ScriptEngine.java @@ -38,6 +38,8 @@ public interface ScriptEngine { JsonNode executeJson(TbMsg msg) throws ScriptException; + ListenableFuture executeJsonAsync(TbMsg msg) throws ScriptException; + String executeToString(TbMsg msg) throws ScriptException; void destroy(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java index 5fc482348d..b8fbeaf74e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java @@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.action; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.ScriptEngine; @@ -27,6 +28,9 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; + +import javax.script.ScriptException; + import static org.thingsboard.common.util.DonAsynchron.withCallback; @@ -67,21 +71,24 @@ public abstract class TbAbstractAlarmNode ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); + t -> ctx.tellFailure(msg, t) + , ctx.getDbCallbackExecutor()); } protected abstract ListenableFuture processAlarm(TbContext ctx, TbMsg msg); protected ListenableFuture buildAlarmDetails(TbContext ctx, TbMsg msg, JsonNode previousDetails) { - return ctx.getJsExecutor().executeAsync(() -> { + try { TbMsg dummyMsg = msg; if (previousDetails != null) { TbMsgMetaData metaData = msg.getMetaData().copy(); metaData.putValue(PREV_ALARM_DETAILS, mapper.writeValueAsString(previousDetails)); dummyMsg = ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, msg.getData()); } - return buildDetailsJsEngine.executeJson(dummyMsg); - }); + return buildDetailsJsEngine.executeJsonAsync(dummyMsg); + } catch (Exception e) { + return Futures.immediateFailedFuture(e); + } } private TbMsg toAlarmMsg(TbContext ctx, AlarmResult alarmResult, TbMsg originalMsg) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java index fb07951368..1884ff2330 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java @@ -26,6 +26,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import org.mockito.stubbing.Answer; import org.thingsboard.common.util.ListeningExecutor; @@ -60,8 +61,6 @@ public class TbAlarmNodeTest { @Mock private TbContext ctx; @Mock - private ListeningExecutor executor; - @Mock private AlarmService alarmService; @Mock @@ -102,7 +101,7 @@ public class TbAlarmNodeTest { metaData.putValue("key", "value"); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L); - when(detailsJs.executeJson(msg)).thenReturn(null); + when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(null)); doAnswer((Answer) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(any(Alarm.class)); @@ -136,8 +135,6 @@ public class TbAlarmNodeTest { .build(); assertEquals(expectedAlarm, actualAlarm); - - verify(executor, times(1)).executeAsync(any(Callable.class)); } @Test @@ -146,7 +143,7 @@ public class TbAlarmNodeTest { metaData.putValue("key", "value"); TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L); - when(detailsJs.executeJson(msg)).thenThrow(new NotImplementedException("message")); + when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFailedFuture(new NotImplementedException("message"))); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(null)); node.onMsg(ctx, msg); @@ -154,7 +151,6 @@ public class TbAlarmNodeTest { verifyError(msg, "message", NotImplementedException.class); verify(ctx).createJsScriptEngine("DETAILS"); - verify(ctx, times(1)).getJsExecutor(); verify(ctx).getAlarmService(); verify(ctx, times(3)).getDbCallbackExecutor(); verify(ctx).logJsEvalRequest(); @@ -172,7 +168,7 @@ public class TbAlarmNodeTest { Alarm clearedAlarm = Alarm.builder().status(CLEARED_ACK).build(); - when(detailsJs.executeJson(msg)).thenReturn(null); + when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(clearedAlarm)); doAnswer((Answer) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(any(Alarm.class)); @@ -207,8 +203,6 @@ public class TbAlarmNodeTest { .build(); assertEquals(expectedAlarm, actualAlarm); - - verify(executor, times(1)).executeAsync(any(Callable.class)); } @Test @@ -220,7 +214,7 @@ public class TbAlarmNodeTest { long oldEndDate = System.currentTimeMillis(); Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).status(ACTIVE_UNACK).severity(WARNING).endTs(oldEndDate).build(); - when(detailsJs.executeJson(msg)).thenReturn(null); + when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(activeAlarm)); doAnswer((Answer) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(activeAlarm); @@ -256,8 +250,6 @@ public class TbAlarmNodeTest { .build(); assertEquals(expectedAlarm, actualAlarm); - - verify(executor, times(1)).executeAsync(any(Callable.class)); } @Test @@ -269,7 +261,7 @@ public class TbAlarmNodeTest { long oldEndDate = System.currentTimeMillis(); Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).status(ACTIVE_UNACK).severity(WARNING).endTs(oldEndDate).build(); -// when(detailsJs.executeJson(msg)).thenReturn(null); + when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(activeAlarm)); when(alarmService.clearAlarm(eq(activeAlarm.getTenantId()), eq(activeAlarm.getId()), org.mockito.Mockito.any(JsonNode.class), anyLong())).thenReturn(Futures.immediateFuture(true)); when(alarmService.findAlarmByIdAsync(eq(activeAlarm.getTenantId()), eq(activeAlarm.getId()))).thenReturn(Futures.immediateFuture(activeAlarm)); @@ -320,12 +312,9 @@ public class TbAlarmNodeTest { when(ctx.createJsScriptEngine("DETAILS")).thenReturn(detailsJs); when(ctx.getTenantId()).thenReturn(tenantId); - when(ctx.getJsExecutor()).thenReturn(executor); when(ctx.getAlarmService()).thenReturn(alarmService); when(ctx.getDbCallbackExecutor()).thenReturn(dbExecutor); - mockJsExecutor(); - node = new TbCreateAlarmNode(); node.init(ctx, nodeConfiguration); } catch (TbNodeException ex) { @@ -344,12 +333,9 @@ public class TbAlarmNodeTest { when(ctx.createJsScriptEngine("DETAILS")).thenReturn(detailsJs); when(ctx.getTenantId()).thenReturn(tenantId); - when(ctx.getJsExecutor()).thenReturn(executor); when(ctx.getAlarmService()).thenReturn(alarmService); when(ctx.getDbCallbackExecutor()).thenReturn(dbExecutor); - mockJsExecutor(); - node = new TbClearAlarmNode(); node.init(ctx, nodeConfiguration); } catch (TbNodeException ex) { @@ -357,18 +343,6 @@ public class TbAlarmNodeTest { } } - private void mockJsExecutor() { - when(ctx.getJsExecutor()).thenReturn(executor); - doAnswer((Answer>) invocationOnMock -> { - try { - Callable task = (Callable) (invocationOnMock.getArguments())[0]; - return Futures.immediateFuture((Boolean) task.call()); - } catch (Throwable th) { - return Futures.immediateFailedFuture(th); - } - }).when(executor).executeAsync(any(Callable.class)); - } - private void verifyError(TbMsg msg, String message, Class expectedClass) { ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); verify(ctx).tellFailure(same(msg), captor.capture()); From 5bff61c2ca4ad1436e8b8324b85a382e3541d9b1 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 11 Dec 2019 15:08:47 +0200 Subject: [PATCH 07/46] Improve JS Executor: add max active scripts parameter --- .../api/jsInvokeMessageProcessor.js | 23 +++++++++++++++++-- .../config/custom-environment-variables.yml | 1 + msa/js-executor/config/default.yml | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/msa/js-executor/api/jsInvokeMessageProcessor.js b/msa/js-executor/api/jsInvokeMessageProcessor.js index 6afc02e89c..ac14bcbd57 100644 --- a/msa/js-executor/api/jsInvokeMessageProcessor.js +++ b/msa/js-executor/api/jsInvokeMessageProcessor.js @@ -27,11 +27,13 @@ const config = require('config'), const scriptBodyTraceFrequency = Number(config.get('script.script_body_trace_frequency')); const useSandbox = config.get('script.use_sandbox') === 'true'; +const maxActiveScripts = Number(config.get('script.max_active_scripts')); function JsInvokeMessageProcessor(producer) { this.producer = producer; this.executor = new JsExecutor(useSandbox); this.scriptMap = {}; + this.scriptIds = []; this.executedScriptsCounter = 0; } @@ -70,7 +72,7 @@ JsInvokeMessageProcessor.prototype.processCompileRequest = function(requestId, r this.executor.compileScript(compileRequest.scriptBody).then( (script) => { - this.scriptMap[scriptId] = script; + this.cacheScript(scriptId, script); var compileResponse = createCompileResponse(scriptId, true); logger.debug('[%s] Sending success compile response, scriptId: [%s]', requestId, scriptId); this.sendResponse(requestId, responseTopic, scriptId, compileResponse); @@ -126,6 +128,10 @@ JsInvokeMessageProcessor.prototype.processReleaseRequest = function(requestId, r var scriptId = getScriptId(releaseRequest); logger.debug('[%s] Processing release request, scriptId: [%s]', requestId, scriptId); if (this.scriptMap[scriptId]) { + var index = this.scriptIds.indexOf(scriptId); + if (index > -1) { + this.scriptIds.splice(index, 1); + } delete this.scriptMap[scriptId]; } var releaseResponse = createReleaseResponse(scriptId, true); @@ -165,7 +171,7 @@ JsInvokeMessageProcessor.prototype.getOrCompileScript = function(scriptId, scrip } else { self.executor.compileScript(scriptBody).then( (script) => { - self.scriptMap[scriptId] = script; + self.cacheScript(scriptId, script); resolve(script); }, (err) => { @@ -176,6 +182,19 @@ JsInvokeMessageProcessor.prototype.getOrCompileScript = function(scriptId, scrip }); } +JsInvokeMessageProcessor.prototype.cacheScript = function(scriptId, script) { + if (!this.scriptMap[scriptId]) { + this.scriptIds.push(scriptId); + while (this.scriptIds.length > maxActiveScripts) { + logger.info('Active scripts count [%s] exceeds maximum limit [%s]', this.scriptIds.length, maxActiveScripts); + const prevScriptId = this.scriptIds.shift(); + logger.info('Removing active script with id [%s]', prevScriptId); + delete this.scriptMap[prevScriptId]; + } + } + this.scriptMap[scriptId] = script; +} + function createRemoteResponse(requestId, compileResponse, invokeResponse, releaseResponse) { const requestIdBits = Utils.UUIDToBits(requestId); return { diff --git a/msa/js-executor/config/custom-environment-variables.yml b/msa/js-executor/config/custom-environment-variables.yml index c3caf15a9a..22b1082f72 100644 --- a/msa/js-executor/config/custom-environment-variables.yml +++ b/msa/js-executor/config/custom-environment-variables.yml @@ -27,3 +27,4 @@ logger: script: use_sandbox: "SCRIPT_USE_SANDBOX" script_body_trace_frequency: "SCRIPT_BODY_TRACE_FREQUENCY" + max_active_scripts: "MAX_ACTIVE_SCRIPTS" diff --git a/msa/js-executor/config/default.yml b/msa/js-executor/config/default.yml index 9688722109..95a847a5bb 100644 --- a/msa/js-executor/config/default.yml +++ b/msa/js-executor/config/default.yml @@ -28,3 +28,4 @@ logger: script: use_sandbox: "true" script_body_trace_frequency: "1000" + max_active_scripts: "1000" From bb05ce046bf98d74a2cf8e5b29104ef62ee53f4e Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Thu, 12 Dec 2019 08:26:19 +0200 Subject: [PATCH 08/46] Suppress spam log message --- .../server/service/state/DefaultDeviceStateService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index c3c8dc7803..ac0644719d 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -289,7 +289,7 @@ public class DefaultDeviceStateService implements DeviceStateService { private void updateState() { long ts = System.currentTimeMillis(); Set deviceIds = new HashSet<>(deviceStates.keySet()); - log.info("Calculating state updates for {} devices", deviceStates.size()); + log.debug("Calculating state updates for {} devices", deviceStates.size()); for (DeviceId deviceId : deviceIds) { DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); if (stateData != null) { From a2cc974865ef16748918a98f8240176d401dddf3 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Fri, 13 Dec 2019 15:53:19 +0200 Subject: [PATCH 09/46] Critical Bug Fix for SQL inserts --- .../AttributeKvInsertRepository.java | 62 ++++++++++--------- .../timescale/TimescaleInsertRepository.java | 33 +++++----- .../sqlts/ts/PsqlLatestInsertRepository.java | 58 ++++++++--------- .../ts/PsqlTimeseriesInsertRepository.java | 33 +++++----- 4 files changed, 96 insertions(+), 90 deletions(-) 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 0a537cbe01..ce7c96d919 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 @@ -143,31 +143,32 @@ public abstract class AttributeKvInsertRepository { int[] result = jdbcTemplate.batchUpdate(BATCH_UPDATE, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { - ps.setString(1, replaceNullChars(entities.get(i).getStrValue())); + AttributeKvEntity kvEntity = entities.get(i); + ps.setString(1, replaceNullChars(kvEntity.getStrValue())); - if (entities.get(i).getLongValue() != null) { - ps.setLong(2, entities.get(i).getLongValue()); + if (kvEntity.getLongValue() != null) { + ps.setLong(2, kvEntity.getLongValue()); } else { ps.setNull(2, Types.BIGINT); } - if (entities.get(i).getDoubleValue() != null) { - ps.setDouble(3, entities.get(i).getDoubleValue()); + if (kvEntity.getDoubleValue() != null) { + ps.setDouble(3, kvEntity.getDoubleValue()); } else { ps.setNull(3, Types.DOUBLE); } - if (entities.get(i).getBooleanValue() != null) { - ps.setBoolean(4, entities.get(i).getBooleanValue()); + if (kvEntity.getBooleanValue() != null) { + ps.setBoolean(4, kvEntity.getBooleanValue()); } else { ps.setNull(4, Types.BOOLEAN); } - ps.setLong(5, entities.get(i).getLastUpdateTs()); - ps.setString(6, entities.get(i).getId().getEntityType().name()); - ps.setString(7, entities.get(i).getId().getEntityId()); - ps.setString(8, entities.get(i).getId().getAttributeType()); - ps.setString(9, entities.get(i).getId().getAttributeKey()); + ps.setLong(5, kvEntity.getLastUpdateTs()); + ps.setString(6, kvEntity.getId().getEntityType().name()); + ps.setString(7, kvEntity.getId().getEntityId()); + ps.setString(8, kvEntity.getId().getAttributeType()); + ps.setString(9, kvEntity.getId().getAttributeKey()); } @Override @@ -193,39 +194,40 @@ public abstract class AttributeKvInsertRepository { jdbcTemplate.batchUpdate(INSERT_OR_UPDATE, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { - ps.setString(1, insertEntities.get(i).getId().getEntityType().name()); - ps.setString(2, insertEntities.get(i).getId().getEntityId()); - ps.setString(3, insertEntities.get(i).getId().getAttributeType()); - ps.setString(4, insertEntities.get(i).getId().getAttributeKey()); - ps.setString(5, replaceNullChars(insertEntities.get(i).getStrValue())); - ps.setString(10, replaceNullChars(insertEntities.get(i).getStrValue())); - - if (insertEntities.get(i).getLongValue() != null) { - ps.setLong(6, insertEntities.get(i).getLongValue()); - ps.setLong(11, insertEntities.get(i).getLongValue()); + AttributeKvEntity kvEntity = insertEntities.get(i); + ps.setString(1, kvEntity.getId().getEntityType().name()); + ps.setString(2, kvEntity.getId().getEntityId()); + ps.setString(3, kvEntity.getId().getAttributeType()); + ps.setString(4, kvEntity.getId().getAttributeKey()); + ps.setString(5, replaceNullChars(kvEntity.getStrValue())); + ps.setString(10, replaceNullChars(kvEntity.getStrValue())); + + if (kvEntity.getLongValue() != null) { + ps.setLong(6, kvEntity.getLongValue()); + ps.setLong(11, kvEntity.getLongValue()); } else { ps.setNull(6, Types.BIGINT); ps.setNull(11, Types.BIGINT); } - if (insertEntities.get(i).getDoubleValue() != null) { - ps.setDouble(7, insertEntities.get(i).getDoubleValue()); - ps.setDouble(12, insertEntities.get(i).getDoubleValue()); + if (kvEntity.getDoubleValue() != null) { + ps.setDouble(7, kvEntity.getDoubleValue()); + ps.setDouble(12, kvEntity.getDoubleValue()); } else { ps.setNull(7, Types.DOUBLE); ps.setNull(12, Types.DOUBLE); } - if (insertEntities.get(i).getBooleanValue() != null) { - ps.setBoolean(8, insertEntities.get(i).getBooleanValue()); - ps.setBoolean(13, insertEntities.get(i).getBooleanValue()); + if (kvEntity.getBooleanValue() != null) { + ps.setBoolean(8, kvEntity.getBooleanValue()); + ps.setBoolean(13, kvEntity.getBooleanValue()); } else { ps.setNull(8, Types.BOOLEAN); ps.setNull(13, Types.BOOLEAN); } - ps.setLong(9, insertEntities.get(i).getLastUpdateTs()); - ps.setLong(14, insertEntities.get(i).getLastUpdateTs()); + ps.setLong(9, kvEntity.getLastUpdateTs()); + ps.setLong(14, kvEntity.getLastUpdateTs()); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleInsertRepository.java index b47c79cb98..a79ea892ed 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleInsertRepository.java @@ -57,34 +57,35 @@ public class TimescaleInsertRepository extends AbstractTimeseriesInsertRepositor jdbcTemplate.batchUpdate(INSERT_OR_UPDATE, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { - ps.setString(1, entities.get(i).getTenantId()); - ps.setString(2, entities.get(i).getEntityId()); - ps.setString(3, entities.get(i).getKey()); - ps.setLong(4, entities.get(i).getTs()); - - if (entities.get(i).getBooleanValue() != null) { - ps.setBoolean(5, entities.get(i).getBooleanValue()); - ps.setBoolean(9, entities.get(i).getBooleanValue()); + TimescaleTsKvEntity tsKvEntity = entities.get(i); + ps.setString(1, tsKvEntity.getTenantId()); + ps.setString(2, tsKvEntity.getEntityId()); + ps.setString(3, tsKvEntity.getKey()); + ps.setLong(4, tsKvEntity.getTs()); + + if (tsKvEntity.getBooleanValue() != null) { + ps.setBoolean(5, tsKvEntity.getBooleanValue()); + ps.setBoolean(9, tsKvEntity.getBooleanValue()); } else { ps.setNull(5, Types.BOOLEAN); ps.setNull(9, Types.BOOLEAN); } - ps.setString(6, replaceNullChars(entities.get(i).getStrValue())); - ps.setString(10, replaceNullChars(entities.get(i).getStrValue())); + ps.setString(6, replaceNullChars(tsKvEntity.getStrValue())); + ps.setString(10, replaceNullChars(tsKvEntity.getStrValue())); - if (entities.get(i).getLongValue() != null) { - ps.setLong(7, entities.get(i).getLongValue()); - ps.setLong(11, entities.get(i).getLongValue()); + if (tsKvEntity.getLongValue() != null) { + ps.setLong(7, tsKvEntity.getLongValue()); + ps.setLong(11, tsKvEntity.getLongValue()); } else { ps.setNull(7, Types.BIGINT); ps.setNull(11, Types.BIGINT); } - if (entities.get(i).getDoubleValue() != null) { - ps.setDouble(8, entities.get(i).getDoubleValue()); - ps.setDouble(12, entities.get(i).getDoubleValue()); + if (tsKvEntity.getDoubleValue() != null) { + ps.setDouble(8, tsKvEntity.getDoubleValue()); + ps.setDouble(12, tsKvEntity.getDoubleValue()); } else { ps.setNull(8, Types.DOUBLE); ps.setNull(12, Types.DOUBLE); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/PsqlLatestInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/PsqlLatestInsertRepository.java index 92252e9d18..e0dad44f3b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/PsqlLatestInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/PsqlLatestInsertRepository.java @@ -65,31 +65,32 @@ public class PsqlLatestInsertRepository extends AbstractLatestInsertRepository { int[] result = jdbcTemplate.batchUpdate(BATCH_UPDATE, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { - ps.setLong(1, entities.get(i).getTs()); + TsKvLatestEntity tsKvLatestEntity = entities.get(i); + ps.setLong(1, tsKvLatestEntity.getTs()); - if (entities.get(i).getBooleanValue() != null) { - ps.setBoolean(2, entities.get(i).getBooleanValue()); + if (tsKvLatestEntity.getBooleanValue() != null) { + ps.setBoolean(2, tsKvLatestEntity.getBooleanValue()); } else { ps.setNull(2, Types.BOOLEAN); } - ps.setString(3, replaceNullChars(entities.get(i).getStrValue())); + ps.setString(3, replaceNullChars(tsKvLatestEntity.getStrValue())); - if (entities.get(i).getLongValue() != null) { - ps.setLong(4, entities.get(i).getLongValue()); + if (tsKvLatestEntity.getLongValue() != null) { + ps.setLong(4, tsKvLatestEntity.getLongValue()); } else { ps.setNull(4, Types.BIGINT); } - if (entities.get(i).getDoubleValue() != null) { - ps.setDouble(5, entities.get(i).getDoubleValue()); + if (tsKvLatestEntity.getDoubleValue() != null) { + ps.setDouble(5, tsKvLatestEntity.getDoubleValue()); } else { ps.setNull(5, Types.DOUBLE); } - ps.setString(6, entities.get(i).getEntityType().name()); - ps.setString(7, entities.get(i).getEntityId()); - ps.setString(8, entities.get(i).getKey()); + ps.setString(6, tsKvLatestEntity.getEntityType().name()); + ps.setString(7, tsKvLatestEntity.getEntityId()); + ps.setString(8, tsKvLatestEntity.getKey()); } @Override @@ -115,35 +116,36 @@ public class PsqlLatestInsertRepository extends AbstractLatestInsertRepository { jdbcTemplate.batchUpdate(INSERT_OR_UPDATE, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { - ps.setString(1, insertEntities.get(i).getEntityType().name()); - ps.setString(2, insertEntities.get(i).getEntityId()); - ps.setString(3, insertEntities.get(i).getKey()); - ps.setLong(4, insertEntities.get(i).getTs()); - ps.setLong(9, insertEntities.get(i).getTs()); - - if (insertEntities.get(i).getBooleanValue() != null) { - ps.setBoolean(5, insertEntities.get(i).getBooleanValue()); - ps.setBoolean(10, insertEntities.get(i).getBooleanValue()); + TsKvLatestEntity tsKvLatestEntity = insertEntities.get(i); + ps.setString(1, tsKvLatestEntity.getEntityType().name()); + ps.setString(2, tsKvLatestEntity.getEntityId()); + ps.setString(3, tsKvLatestEntity.getKey()); + ps.setLong(4, tsKvLatestEntity.getTs()); + ps.setLong(9, tsKvLatestEntity.getTs()); + + if (tsKvLatestEntity.getBooleanValue() != null) { + ps.setBoolean(5, tsKvLatestEntity.getBooleanValue()); + ps.setBoolean(10, tsKvLatestEntity.getBooleanValue()); } else { ps.setNull(5, Types.BOOLEAN); ps.setNull(10, Types.BOOLEAN); } - ps.setString(6, replaceNullChars(entities.get(i).getStrValue())); - ps.setString(11, replaceNullChars(entities.get(i).getStrValue())); + ps.setString(6, replaceNullChars(tsKvLatestEntity.getStrValue())); + ps.setString(11, replaceNullChars(tsKvLatestEntity.getStrValue())); - if (insertEntities.get(i).getLongValue() != null) { - ps.setLong(7, insertEntities.get(i).getLongValue()); - ps.setLong(12, insertEntities.get(i).getLongValue()); + if (tsKvLatestEntity.getLongValue() != null) { + ps.setLong(7, tsKvLatestEntity.getLongValue()); + ps.setLong(12, tsKvLatestEntity.getLongValue()); } else { ps.setNull(7, Types.BIGINT); ps.setNull(12, Types.BIGINT); } - if (insertEntities.get(i).getDoubleValue() != null) { - ps.setDouble(8, insertEntities.get(i).getDoubleValue()); - ps.setDouble(13, insertEntities.get(i).getDoubleValue()); + if (tsKvLatestEntity.getDoubleValue() != null) { + ps.setDouble(8, tsKvLatestEntity.getDoubleValue()); + ps.setDouble(13, tsKvLatestEntity.getDoubleValue()); } else { ps.setNull(8, Types.DOUBLE); ps.setNull(13, Types.DOUBLE); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/PsqlTimeseriesInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/PsqlTimeseriesInsertRepository.java index edc37822b1..e1c8eb7ee2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/PsqlTimeseriesInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/PsqlTimeseriesInsertRepository.java @@ -99,34 +99,35 @@ public class PsqlTimeseriesInsertRepository extends AbstractTimeseriesInsertRepo jdbcTemplate.batchUpdate(INSERT_OR_UPDATE, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { - ps.setString(1, entities.get(i).getEntityType().name()); - ps.setString(2, entities.get(i).getEntityId()); - ps.setString(3, entities.get(i).getKey()); - ps.setLong(4, entities.get(i).getTs()); - - if (entities.get(i).getBooleanValue() != null) { - ps.setBoolean(5, entities.get(i).getBooleanValue()); - ps.setBoolean(9, entities.get(i).getBooleanValue()); + TsKvEntity tsKvEntity = entities.get(i); + ps.setString(1, tsKvEntity.getEntityType().name()); + ps.setString(2, tsKvEntity.getEntityId()); + ps.setString(3, tsKvEntity.getKey()); + ps.setLong(4, tsKvEntity.getTs()); + + if (tsKvEntity.getBooleanValue() != null) { + ps.setBoolean(5, tsKvEntity.getBooleanValue()); + ps.setBoolean(9, tsKvEntity.getBooleanValue()); } else { ps.setNull(5, Types.BOOLEAN); ps.setNull(9, Types.BOOLEAN); } - ps.setString(6, replaceNullChars(entities.get(i).getStrValue())); - ps.setString(10, replaceNullChars(entities.get(i).getStrValue())); + ps.setString(6, replaceNullChars(tsKvEntity.getStrValue())); + ps.setString(10, replaceNullChars(tsKvEntity.getStrValue())); - if (entities.get(i).getLongValue() != null) { - ps.setLong(7, entities.get(i).getLongValue()); - ps.setLong(11, entities.get(i).getLongValue()); + if (tsKvEntity.getLongValue() != null) { + ps.setLong(7, tsKvEntity.getLongValue()); + ps.setLong(11, tsKvEntity.getLongValue()); } else { ps.setNull(7, Types.BIGINT); ps.setNull(11, Types.BIGINT); } - if (entities.get(i).getDoubleValue() != null) { - ps.setDouble(8, entities.get(i).getDoubleValue()); - ps.setDouble(12, entities.get(i).getDoubleValue()); + if (tsKvEntity.getDoubleValue() != null) { + ps.setDouble(8, tsKvEntity.getDoubleValue()); + ps.setDouble(12, tsKvEntity.getDoubleValue()); } else { ps.setNull(8, Types.DOUBLE); ps.setNull(12, Types.DOUBLE); From f23cfc98807677e8edd4247950ddd63c4cabb104 Mon Sep 17 00:00:00 2001 From: VoBa Date: Mon, 16 Dec 2019 16:06:51 +0200 Subject: [PATCH 10/46] Added device creation with token (#2272) * Added device creation with token * Fixes after code review * Added device creation with token --- .../server/controller/DeviceController.java | 5 ++-- .../server/dao/device/DeviceService.java | 2 ++ .../server/dao/device/DeviceServiceImpl.java | 12 +++++++- .../thingsboard/client/tools/RestClient.java | 29 ++++++++++++++----- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 698dcfb3f3..7ab4ab07a9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -82,7 +82,8 @@ public class DeviceController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device", method = RequestMethod.POST) @ResponseBody - public Device saveDevice(@RequestBody Device device) throws ThingsboardException { + public Device saveDevice(@RequestBody Device device, + @RequestParam(name = "accessToken", required = false) String accessToken) throws ThingsboardException { try { device.setTenantId(getCurrentUser().getTenantId()); @@ -91,7 +92,7 @@ public class DeviceController extends BaseController { accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, device.getId(), device); - Device savedDevice = checkNotNull(deviceService.saveDevice(device)); + Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); actorService .onDeviceNameOrTypeUpdate( diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index 793bb9829b..b9940d73e3 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -37,6 +37,8 @@ public interface DeviceService { Device saveDevice(Device device); + Device saveDeviceWithAccessToken(Device device, String accessToken); + Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId); Device unassignDeviceFromCustomer(TenantId tenantId, DeviceId deviceId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index a26e275a96..0618d3fcf8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -119,9 +119,19 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe return deviceOpt.orElse(null); } + @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}") + @Override + public Device saveDeviceWithAccessToken(Device device, String accessToken) { + return doSaveDevice(device, accessToken); + } + @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}") @Override public Device saveDevice(Device device) { + return doSaveDevice(device, null); + } + + private Device doSaveDevice(Device device, String accessToken) { log.trace("Executing saveDevice [{}]", device); deviceValidator.validate(device, Device::getTenantId); Device savedDevice; @@ -143,7 +153,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe DeviceCredentials deviceCredentials = new DeviceCredentials(); deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId())); deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); - deviceCredentials.setCredentialsId(RandomStringUtils.randomAlphanumeric(20)); + deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20)); deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials); } return savedDevice; diff --git a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java index 97ce718cc8..180e7f6f57 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java +++ b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java @@ -225,13 +225,6 @@ public class RestClient implements ClientHttpRequestInterceptor { return restTemplate.postForEntity(baseURL + "/api/customer", customer, Customer.class).getBody(); } - public Device createDevice(String name, String type) { - Device device = new Device(); - device.setName(name); - device.setType(type); - return restTemplate.postForEntity(baseURL + "/api/device", device, Device.class).getBody(); - } - public DeviceCredentials updateDeviceCredentials(DeviceId deviceId, String token) { DeviceCredentials deviceCredentials = getCredentials(deviceId); deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); @@ -239,10 +232,30 @@ public class RestClient implements ClientHttpRequestInterceptor { return saveDeviceCredentials(deviceCredentials); } + public Device createDevice(String name, String type) { + Device device = new Device(); + device.setName(name); + device.setType(type); + return doCreateDevice(device, null); + } + public Device createDevice(Device device) { - return restTemplate.postForEntity(baseURL + "/api/device", device, Device.class).getBody(); + return doCreateDevice(device, null); } + public Device createDevice(Device device, String accessToken) { + return doCreateDevice(device, accessToken); + } + + private Device doCreateDevice(Device device, String accessToken) { + Map params = new HashMap<>(); + String deviceCreationUrl = "/api/device"; + if (!StringUtils.isEmpty(accessToken)) { + deviceCreationUrl = deviceCreationUrl + "?accessToken={accessToken}"; + params.put("accessToken", accessToken); + } + return restTemplate.postForEntity(baseURL + deviceCreationUrl, device, Device.class, params).getBody(); + } public Asset createAsset(Asset asset) { return restTemplate.postForEntity(baseURL + "/api/asset", asset, Asset.class).getBody(); } From cfe7e4260274d90ad992214e4cdba6d7733c9200 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Wed, 18 Dec 2019 18:24:28 +0200 Subject: [PATCH 11/46] JS Stats for Nashorn JS Executor --- .../AbstractNashornJsInvokeService.java | 107 ++++++++++++++---- .../server/service/script/JsStatCallback.java | 31 +++++ .../src/main/resources/thingsboard.yml | 5 + 3 files changed, 123 insertions(+), 20 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java 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 62e7c24b1a..807c43ffa7 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 @@ -15,21 +15,33 @@ */ 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 delight.nashornsandbox.NashornSandbox; import delight.nashornsandbox.NashornSandboxes; import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +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.scheduling.annotation.Scheduled; +import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptException; import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; @Slf4j public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeService { @@ -37,9 +49,46 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer private NashornSandbox sandbox; private ScriptEngine engine; private ExecutorService monitorExecutorService; + private ScheduledExecutorService timeoutExecutorService; + + private final AtomicInteger jsPushedMsgs = new AtomicInteger(0); + private final AtomicInteger jsInvokeMsgs = new AtomicInteger(0); + private final AtomicInteger jsEvalMsgs = new AtomicInteger(0); + private final AtomicInteger jsFailedMsgs = new AtomicInteger(0); + private final AtomicInteger jsTimeoutMsgs = new AtomicInteger(0); + private final FutureCallback evalCallback = new JsStatCallback(jsEvalMsgs, jsTimeoutMsgs, jsFailedMsgs); + private final FutureCallback invokeCallback = new JsStatCallback(jsInvokeMsgs, jsTimeoutMsgs, jsFailedMsgs); + + @Autowired + @Getter + private JsExecutorService jsExecutor; + + @Value("${js.local.max_requests_timeout:0}") + private long maxRequestsTimeout; + + @Value("${js.local.stats.enabled:false}") + private boolean statsEnabled; + + @Scheduled(fixedDelayString = "${js.remote.stats.print_interval_ms:10000}") + public void printStats() { + if (statsEnabled) { + int pushedMsgs = jsPushedMsgs.getAndSet(0); + int invokeMsgs = jsInvokeMsgs.getAndSet(0); + int evalMsgs = jsEvalMsgs.getAndSet(0); + int failed = jsFailedMsgs.getAndSet(0); + int timedOut = jsTimeoutMsgs.getAndSet(0); + if (pushedMsgs > 0 || invokeMsgs > 0 || evalMsgs > 0 || failed > 0 || timedOut > 0) { + log.info("Nashorn JS Invoke Stats: pushed [{}] received [{}] invoke [{}] eval [{}] failed [{}] timedOut [{}]", + pushedMsgs, invokeMsgs + evalMsgs, invokeMsgs, evalMsgs, failed, timedOut); + } + } + } @PostConstruct public void init() { + if (maxRequestsTimeout > 0) { + timeoutExecutorService = Executors.newSingleThreadScheduledExecutor(); + } if (useJsSandbox()) { sandbox = NashornSandboxes.create(); monitorExecutorService = Executors.newWorkStealingPool(getMonitorThreadPoolSize()); @@ -59,6 +108,9 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer if (monitorExecutorService != null) { monitorExecutorService.shutdownNow(); } + if (timeoutExecutorService != null) { + timeoutExecutorService.shutdownNow(); + } } protected abstract boolean useJsSandbox(); @@ -69,34 +121,49 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer @Override protected ListenableFuture doEval(UUID scriptId, String functionName, String jsScript) { - try { - if (useJsSandbox()) { - sandbox.eval(jsScript); - } else { - engine.eval(jsScript); + jsPushedMsgs.incrementAndGet(); + ListenableFuture result = jsExecutor.executeAsync(() -> { + try { + if (useJsSandbox()) { + sandbox.eval(jsScript); + } else { + engine.eval(jsScript); + } + scriptIdToNameMap.put(scriptId, functionName); + return scriptId; + } catch (Exception e) { + log.warn("Failed to compile JS script: {}", e.getMessage(), e); + throw new ExecutionException(e); } - scriptIdToNameMap.put(scriptId, functionName); - } catch (Exception e) { - log.warn("Failed to compile JS script: {}", e.getMessage(), e); - return Futures.immediateFailedFuture(e); + }); + if (maxRequestsTimeout > 0) { + result = Futures.withTimeout(result, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); } - return Futures.immediateFuture(scriptId); + Futures.addCallback(result, evalCallback); + return result; } @Override protected ListenableFuture doInvokeFunction(UUID scriptId, String functionName, Object[] args) { - try { - Object result; - if (useJsSandbox()) { - result = sandbox.getSandboxedInvocable().invokeFunction(functionName, args); - } else { - result = ((Invocable) engine).invokeFunction(functionName, args); + jsPushedMsgs.incrementAndGet(); + ListenableFuture result = jsExecutor.executeAsync(() -> { + try { + if (useJsSandbox()) { + return sandbox.getSandboxedInvocable().invokeFunction(functionName, args); + } else { + return ((Invocable) engine).invokeFunction(functionName, args); + } + } catch (Exception e) { + onScriptExecutionError(scriptId); + throw new ExecutionException(e); } - return Futures.immediateFuture(result); - } catch (Exception e) { - onScriptExecutionError(scriptId); - return Futures.immediateFailedFuture(e); + }); + + if (maxRequestsTimeout > 0) { + result = Futures.withTimeout(result, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); } + Futures.addCallback(result, invokeCallback); + return result; } protected void doRelease(UUID scriptId, String functionName) throws ScriptException { diff --git a/application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java b/application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java new file mode 100644 index 0000000000..cceba04f4f --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java @@ -0,0 +1,31 @@ +package org.thingsboard.server.service.script; + +import com.google.common.util.concurrent.FutureCallback; +import lombok.AllArgsConstructor; + +import javax.annotation.Nullable; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +@AllArgsConstructor +public class JsStatCallback implements FutureCallback { + + private final AtomicInteger jsSuccessMsgs; + private final AtomicInteger jsTimeoutMsgs; + private final AtomicInteger jsFailedMsgs; + + + @Override + public void onSuccess(@Nullable T result) { + jsSuccessMsgs.incrementAndGet(); + } + + @Override + public void onFailure(Throwable t) { + if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) { + jsTimeoutMsgs.incrementAndGet(); + } else { + jsFailedMsgs.incrementAndGet(); + } + } +} diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index fcf62a659b..c03240e17f 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -464,6 +464,11 @@ js: max_cpu_time: "${LOCAL_JS_SANDBOX_MAX_CPU_TIME:3000}" # Maximum allowed JavaScript execution errors before JavaScript will be blacklisted max_errors: "${LOCAL_JS_SANDBOX_MAX_ERRORS:3}" + # JS Eval max request timeout. 0 - no timeout + max_requests_timeout: "${LOCAL_JS_MAX_REQUEST_TIMEOUT:0}" + stats: + enabled: "${TB_JS_LOCAL_STATS_ENABLED:false}" + print_interval_ms: "${TB_JS_LOCAL_STATS_PRINT_INTERVAL_MS:10000}" # Remote JavaScript environment properties remote: # JS Eval request topic From 91b07f6c9000a9d9a9c1a3b68bfe6e521ed2a0b4 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Thu, 19 Dec 2019 16:15:27 +0200 Subject: [PATCH 12/46] Download Dependencies maven profile --- pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index 898c417300..0cbbd05bea 100755 --- a/pom.xml +++ b/pom.xml @@ -115,6 +115,15 @@ true + + + + download-dependencies + + true + true + + From 43503f9c61a9ad4389359c868f4d9a66a2097e3f Mon Sep 17 00:00:00 2001 From: vlad Date: Thu, 19 Dec 2019 18:00:24 +0200 Subject: [PATCH 13/46] Activity event support for Copy to view node added --- .../server/service/state/DefaultDeviceStateService.java | 6 ++---- .../engine/action/TbCopyAttributesToEntityViewNode.java | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index ac0644719d..eb0f7d09c0 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -70,10 +70,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import static org.thingsboard.server.common.data.DataConstants.ACTIVITY_EVENT; -import static org.thingsboard.server.common.data.DataConstants.CONNECT_EVENT; -import static org.thingsboard.server.common.data.DataConstants.DISCONNECT_EVENT; -import static org.thingsboard.server.common.data.DataConstants.INACTIVITY_EVENT; +import static org.thingsboard.server.common.data.DataConstants.*; /** * Created by ashvayka on 01.05.18. @@ -334,6 +331,7 @@ public class DefaultDeviceStateService implements DeviceStateService { DeviceState state = stateData.getState(); long ts = System.currentTimeMillis(); stateData.getState().setLastActivityTime(ts); + stateData.getMetaData().putValue("scope", SERVER_SCOPE); pushRuleEngineMessage(stateData, ACTIVITY_EVENT); save(deviceId, LAST_ACTIVITY_TIME, ts); 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 603363b350..bcc89a0e4e 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 @@ -71,6 +71,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { public void onMsg(TbContext ctx, TbMsg msg) { if (DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) || DataConstants.ATTRIBUTES_DELETED.equals(msg.getType()) || + DataConstants.ACTIVITY_EVENT.equals(msg.getType()) || SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType())) { if (!msg.getMetaData().getData().isEmpty()) { long now = System.currentTimeMillis(); @@ -87,7 +88,8 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { long endTime = entityView.getEndTimeMs(); if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) { if (DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) || - SessionMsgType.POST_ATTRIBUTES_REQUEST.name().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()); From 27d0fc3b0a21724755ba1a3df3520b62fc8676f9 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Fri, 20 Dec 2019 12:12:33 +0200 Subject: [PATCH 14/46] Missing License Header --- .../server/service/script/JsStatCallback.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java b/application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java index cceba04f4f..a1cf38b434 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java +++ b/application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2019 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.FutureCallback; From 0ea991019a1a5fd8b61ff096159226417dda3d6f Mon Sep 17 00:00:00 2001 From: vlad Date: Fri, 20 Dec 2019 12:32:12 +0200 Subject: [PATCH 15/46] Activity added --- application/src/main/resources/thingsboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index fcf62a659b..2173c39670 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -384,7 +384,7 @@ spring: driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" username: "${SPRING_DATASOURCE_USERNAME:postgres}" - password: "${SPRING_DATASOURCE_PASSWORD:postgres}" + password: "${SPRING_DATASOURCE_PASSWORD:123456}" hikari: maximumPoolSize: "${SPRING_DATASOURCE_MAXIMUM_POOL_SIZE:50}" From cacdf09eef1a1f68588e5a5d4349c0458c9043a6 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Fri, 20 Dec 2019 13:50:07 +0200 Subject: [PATCH 16/46] More clear thread names --- .../actors/service/DefaultActorService.java | 2 - .../server/controller/RpcController.java | 15 +----- .../controller/TelemetryController.java | 3 +- .../cluster/discovery/ZkDiscoveryService.java | 3 +- .../service/rpc/DefaultDeviceRpcService.java | 3 +- .../AbstractNashornJsInvokeService.java | 3 +- .../service/security/AccessValidator.java | 3 +- .../state/DefaultDeviceStateService.java | 3 +- .../DefaultTelemetrySubscriptionService.java | 5 +- .../BaseRuleChainTransactionService.java | 3 +- .../RemoteRuleEngineTransportService.java | 3 +- .../service/update/DefaultUpdateService.java | 3 +- .../src/main/resources/thingsboard.yml | 4 -- common/transport/transport-api/pom.xml | 4 ++ .../service/AbstractTransportService.java | 3 +- .../service/RemoteTransportService.java | 3 +- .../common/util/ThingsBoardThreadFactory.java | 54 +++++++++++++++++++ .../server/dao/alarm/BaseAlarmService.java | 3 +- .../dao/audit/CassandraAuditLogDao.java | 3 +- .../dao/nosql/CassandraAbstractAsyncDao.java | 3 +- .../sql/ScheduledLogExecutorComponent.java | 3 +- .../server/dao/sql/TbSqlBlockingQueue.java | 3 +- .../dao/sqlts/AbstractSqlTimeseriesDao.java | 38 ------------- .../timescale/TimescaleTimeseriesDao.java | 4 +- .../server/dao/sqlts/ts/JpaTimeseriesDao.java | 2 +- .../util/AbstractBufferedRateExecutor.java | 5 +- 26 files changed, 100 insertions(+), 81 deletions(-) create mode 100644 common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java diff --git a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java index 852fbe2884..2979d9310b 100644 --- a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java +++ b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java @@ -95,8 +95,6 @@ public class DefaultActorService implements ActorService { private ActorRef rpcManagerActor; - private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); - @PostConstruct public void initActorSystem() { log.info("Initializing Actor system."); diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcController.java b/application/src/main/java/org/thingsboard/server/controller/RpcController.java index 3b624e9b94..0980ca068c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcController.java @@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.rule.engine.api.RpcError; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; @@ -76,20 +77,6 @@ public class RpcController extends BaseController { @Autowired private AccessValidator accessValidator; - private ExecutorService executor; - - @PostConstruct - public void initExecutor() { - executor = Executors.newSingleThreadExecutor(); - } - - @PreDestroy - public void shutdownExecutor() { - if (executor != null) { - executor.shutdownNow(); - } - } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index d46e6475c0..a7987cec3d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -37,6 +37,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; @@ -108,7 +109,7 @@ public class TelemetryController extends BaseController { @PostConstruct public void initExecutor() { - executor = Executors.newSingleThreadExecutor(); + executor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("telemetry-controller")); } @PreDestroy diff --git a/application/src/main/java/org/thingsboard/server/service/cluster/discovery/ZkDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/cluster/discovery/ZkDiscoveryService.java index e44c28dc39..a34c8dded0 100644 --- a/application/src/main/java/org/thingsboard/server/service/cluster/discovery/ZkDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/cluster/discovery/ZkDiscoveryService.java @@ -41,6 +41,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.springframework.util.Assert; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.actors.service.ActorService; import org.thingsboard.server.common.msg.cluster.ServerAddress; import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; @@ -114,7 +115,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi Assert.notNull(zkConnectionTimeout, MiscUtils.missingProperty("zk.connection_timeout_ms")); Assert.notNull(zkSessionTimeout, MiscUtils.missingProperty("zk.session_timeout_ms")); - reconnectExecutorService = Executors.newSingleThreadExecutor(); + reconnectExecutorService = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("zk-discovery")); log.info("Initializing discovery service using ZK connect string: {}", zkUrl); diff --git a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultDeviceRpcService.java b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultDeviceRpcService.java index 2e1078fa8e..5fe8cb30df 100644 --- a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultDeviceRpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultDeviceRpcService.java @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.rule.engine.api.RpcError; import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; import org.thingsboard.server.actors.service.ActorService; @@ -83,7 +84,7 @@ public class DefaultDeviceRpcService implements DeviceRpcService { @PostConstruct public void initExecutor() { - rpcCallBackExecutor = Executors.newSingleThreadScheduledExecutor(); + rpcCallBackExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("rpc-callback")); } @PreDestroy 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 807c43ffa7..6c0afbf2e2 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 @@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import javax.annotation.Nullable; import javax.annotation.PostConstruct; @@ -87,7 +88,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer @PostConstruct public void init() { if (maxRequestsTimeout > 0) { - timeoutExecutorService = Executors.newSingleThreadScheduledExecutor(); + timeoutExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("nashorn-js-timeout")); } if (useJsSandbox()) { sandbox = NashornSandboxes.create(); diff --git a/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java b/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java index 6b6e2553fa..f49db67e96 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java +++ b/application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java @@ -24,6 +24,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.context.request.async.DeferredResult; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityView; @@ -105,7 +106,7 @@ public class AccessValidator { @PostConstruct public void initExecutor() { - executor = Executors.newSingleThreadExecutor(); + executor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("access-validator")); } @PreDestroy diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index ac0644719d..f162d05419 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -31,6 +31,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.actors.service.ActorService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; @@ -144,7 +145,7 @@ public class DefaultDeviceStateService implements DeviceStateService { @PostConstruct public void init() { // Should be always single threaded due to absence of locks. - queueExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadScheduledExecutor()); + queueExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("device-state"))); queueExecutor.submit(this::initStateFromDB); queueExecutor.scheduleAtFixedRate(this::updateState, new Random().nextInt(defaultStateCheckIntervalInSec), defaultStateCheckIntervalInSec, TimeUnit.SECONDS); //TODO: schedule persistence in v2.1; 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 c4ddcf654b..a829fa371b 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 @@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.server.actors.service.ActorService; @@ -110,8 +111,8 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @PostConstruct public void initExecutor() { - tsCallBackExecutor = Executors.newSingleThreadExecutor(); - wsCallBackExecutor = Executors.newSingleThreadExecutor(); + tsCallBackExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("ts-sub-callback")); + wsCallBackExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("ws-sub-callback")); } @PreDestroy diff --git a/application/src/main/java/org/thingsboard/server/service/transaction/BaseRuleChainTransactionService.java b/application/src/main/java/org/thingsboard/server/service/transaction/BaseRuleChainTransactionService.java index b40e2b93fd..080478c4c4 100644 --- a/application/src/main/java/org/thingsboard/server/service/transaction/BaseRuleChainTransactionService.java +++ b/application/src/main/java/org/thingsboard/server/service/transaction/BaseRuleChainTransactionService.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.rule.engine.api.RuleChainTransactionService; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.msg.TbMsg; @@ -71,7 +72,7 @@ public class BaseRuleChainTransactionService implements RuleChainTransactionServ @PostConstruct public void init() { - timeoutExecutor = Executors.newSingleThreadExecutor(); + timeoutExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("rule-chain-transaction")); executeOnTimeout(); } diff --git a/application/src/main/java/org/thingsboard/server/service/transport/RemoteRuleEngineTransportService.java b/application/src/main/java/org/thingsboard/server/service/transport/RemoteRuleEngineTransportService.java index 1c1c7be483..d2c18b2406 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/RemoteRuleEngineTransportService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/RemoteRuleEngineTransportService.java @@ -32,6 +32,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.common.msg.cluster.ServerAddress; import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; @@ -103,7 +104,7 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ private TBKafkaConsumerTemplate ruleEngineConsumer; private TBKafkaProducerTemplate notificationsProducer; - private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(); + private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-main-consumer")); private volatile boolean stopped = false; diff --git a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java index 14cbf95861..479f5afcb9 100644 --- a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java @@ -22,6 +22,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.UpdateMessage; import javax.annotation.PostConstruct; @@ -50,7 +51,7 @@ public class DefaultUpdateService implements UpdateService { @Value("${updates.enabled}") private boolean updatesEnabled; - private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, ThingsBoardThreadFactory.forName("tb-update-service")); private ScheduledFuture checkUpdatesFuture = null; private RestTemplate restClient = new RestTemplate(); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index c03240e17f..b3662a60e1 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -195,10 +195,6 @@ cassandra: # SQL configuration parameters sql: - # Specify executor service type used to perform timeseries insert tasks: SINGLE or FIXED - ts_inserts_executor_type: "${SQL_TS_INSERTS_EXECUTOR_TYPE:fixed}" - # Specify thread pool size for FIXED executor service type - ts_inserts_fixed_thread_pool_size: "${SQL_TS_INSERTS_FIXED_THREAD_POOL_SIZE:200}" # Specify batch size for persisting attribute updates attributes: batch_size: "${SQL_ATTRIBUTES_BATCH_SIZE:10000}" diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index dc6cbfd1ba..25a9b456fb 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -44,6 +44,10 @@ org.thingsboard.common message + + org.thingsboard.common + util + org.thingsboard.common queue diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/AbstractTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/AbstractTransportService.java index b09e94202d..bcafa177a4 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/AbstractTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/AbstractTransportService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.common.transport.service; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; @@ -300,7 +301,7 @@ public abstract class AbstractTransportService implements TransportService { new TbRateLimits(perTenantLimitsConf); new TbRateLimits(perDevicesLimitsConf); } - this.schedulerExecutor = Executors.newSingleThreadScheduledExecutor(); + this.schedulerExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("transport-scheduler")); this.transportCallbackExecutor = Executors.newWorkStealingPool(20); this.schedulerExecutor.scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) sessionReportTimeout), sessionReportTimeout, TimeUnit.MILLISECONDS); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/RemoteTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/RemoteTransportService.java index 632ce16bc1..5397837b68 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/RemoteTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/RemoteTransportService.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; @@ -100,7 +101,7 @@ public class RemoteTransportService extends AbstractTransportService { private TBKafkaProducerTemplate ruleEngineProducer; private TBKafkaConsumerTemplate mainConsumer; - private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(); + private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("remote-transport-consumer")); private volatile boolean stopped = false; diff --git a/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java b/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java new file mode 100644 index 0000000000..ff08349bd4 --- /dev/null +++ b/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java @@ -0,0 +1,54 @@ +/** + * Copyright © 2016-2019 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.common.util; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Copy of Executors.DefaultThreadFactory but with ability to set name of the pool + */ +public class ThingsBoardThreadFactory implements ThreadFactory { + private static final AtomicInteger poolNumber = new AtomicInteger(1); + private final ThreadGroup group; + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix; + + public static ThingsBoardThreadFactory forName(String name) { + return new ThingsBoardThreadFactory(name); + } + + private ThingsBoardThreadFactory(String name) { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + namePrefix = name + "-" + + poolNumber.getAndIncrement() + + "-thread-"; + } + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, + namePrefix + threadNumber.getAndIncrement(), + 0); + if (t.isDaemon()) + t.setDaemon(false); + if (t.getPriority() != Thread.NORM_PRIORITY) + t.setPriority(Thread.NORM_PRIORITY); + return t; + } +} 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 8a4279fe7f..d46445778d 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 @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.alarm.Alarm; @@ -81,7 +82,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @PostConstruct public void startExecutor() { - readResultsProcessingExecutor = Executors.newCachedThreadPool(); + readResultsProcessingExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("alarm-service")); } @PreDestroy diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java b/dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java index 675a24a7f7..d75014a389 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java @@ -29,6 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.AuditLog; import org.thingsboard.server.common.data.id.CustomerId; @@ -117,7 +118,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao implements TbSqlQueue { @Override public void init(ScheduledLogExecutorComponent logExecutor, Consumer> saveFunction) { this.logExecutor = logExecutor; - executor = Executors.newSingleThreadExecutor(); + executor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("sql-queue-" + params.getLogName().toLowerCase())); executor.submit(() -> { String logName = params.getLogName(); int batchSize = params.getBatchSize(); 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 a7efad1e88..15a012df66 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 @@ -44,44 +44,6 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx private static final String DESC_ORDER = "DESC"; - @Value("${sql.ts_inserts_executor_type}") - private String insertExecutorType; - - @Value("${sql.ts_inserts_fixed_thread_pool_size}") - private int insertFixedThreadPoolSize; - - @Value("${spring.datasource.hikari.maximumPoolSize}") - private int maximumPoolSize; - - protected ListeningExecutorService insertService; - - @PostConstruct - void init() { - Optional executorTypeOptional = TsInsertExecutorType.parse(insertExecutorType); - TsInsertExecutorType executorType; - executorType = executorTypeOptional.orElse(TsInsertExecutorType.FIXED); - switch (executorType) { - case SINGLE: - insertService = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); - break; - case FIXED: - case CACHED: - int poolSize = insertFixedThreadPoolSize; - if (poolSize <= 0) { - poolSize = maximumPoolSize * 4; - } - insertService = MoreExecutors.listeningDecorator(Executors.newWorkStealingPool(poolSize)); - break; - } - } - - @PreDestroy - void preDestroy() { - if (insertService != null) { - insertService.shutdown(); - } - } - protected ListenableFuture> processFindAllAsync(TenantId tenantId, EntityId entityId, List queries) { List>> futures = queries .stream() diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java index 961f545567..cbd2d2cdc8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java @@ -170,12 +170,12 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements @Override public ListenableFuture savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) { - return insertService.submit(() -> null); + return Futures.immediateFuture(null); } @Override public ListenableFuture saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) { - return insertService.submit(() -> null); + return Futures.immediateFuture(null); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/JpaTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/JpaTimeseriesDao.java index 7c198d9a73..71b156b81f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/JpaTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/ts/JpaTimeseriesDao.java @@ -334,7 +334,7 @@ public class JpaTimeseriesDao extends AbstractSqlTimeseriesDao implements Timese @Override public ListenableFuture savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) { - return insertService.submit(() -> null); + return Futures.immediateFuture(null); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java b/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java index a553aa5f9c..54fdfbf2d5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.tools.TbRateLimits; import org.thingsboard.server.dao.nosql.CassandraStatementTask; @@ -67,9 +68,9 @@ public abstract class AbstractBufferedRateExecutor(queueLimit); - this.dispatcherExecutor = Executors.newFixedThreadPool(dispatcherThreads); + this.dispatcherExecutor = Executors.newFixedThreadPool(dispatcherThreads, ThingsBoardThreadFactory.forName("nosql-dispatcher")); this.callbackExecutor = Executors.newWorkStealingPool(callbackThreads); - this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(); + this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("nosql-timeout")); this.perTenantLimitsEnabled = perTenantLimitsEnabled; this.perTenantLimitsConfiguration = perTenantLimitsConfiguration; for (int i = 0; i < dispatcherThreads; i++) { From 95752ff3b9d70da946c1fb6a6f714943b6fd73a2 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Fri, 20 Dec 2019 15:58:55 +0200 Subject: [PATCH 17/46] Performance Improvement for Device State Service --- .../state/DefaultDeviceStateService.java | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index f162d05419..0a6ce7f158 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -141,6 +141,8 @@ public class DefaultDeviceStateService implements DeviceStateService { private ListeningScheduledExecutorService queueExecutor; private ConcurrentMap> tenantDevices = new ConcurrentHashMap<>(); private ConcurrentMap deviceStates = new ConcurrentHashMap<>(); + private ConcurrentMap deviceLastReportedActivity = new ConcurrentHashMap<>(); + private ConcurrentMap deviceLastSavedActivity = new ConcurrentHashMap<>(); @PostConstruct public void init() { @@ -175,6 +177,7 @@ public class DefaultDeviceStateService implements DeviceStateService { @Override public void onDeviceActivity(DeviceId deviceId) { + deviceLastReportedActivity.put(deviceId, System.currentTimeMillis()); queueExecutor.submit(() -> onDeviceActivitySync(deviceId)); } @@ -245,6 +248,8 @@ public class DefaultDeviceStateService implements DeviceStateService { tenantDeviceSet.remove(device.getId()); } deviceStates.remove(device.getId()); + deviceLastReportedActivity.remove(device.getId()); + deviceLastSavedActivity.remove(device.getId()); } } try { @@ -305,6 +310,8 @@ public class DefaultDeviceStateService implements DeviceStateService { } else { log.debug("[{}] Device that belongs to other server is detected and removed.", deviceId); deviceStates.remove(deviceId); + deviceLastReportedActivity.remove(deviceId); + deviceLastSavedActivity.remove(deviceId); } } } @@ -330,17 +337,20 @@ public class DefaultDeviceStateService implements DeviceStateService { } private void onDeviceActivitySync(DeviceId deviceId) { - DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); - if (stateData != null) { - DeviceState state = stateData.getState(); - long ts = System.currentTimeMillis(); - stateData.getState().setLastActivityTime(ts); - pushRuleEngineMessage(stateData, ACTIVITY_EVENT); - save(deviceId, LAST_ACTIVITY_TIME, ts); - - if (!state.isActive()) { - state.setActive(true); - save(deviceId, ACTIVITY_STATE, state.isActive()); + long lastReportedActivity = deviceLastReportedActivity.getOrDefault(deviceId, 0L); + long lastSavedActivity = deviceLastSavedActivity.getOrDefault(deviceId, 0L); + if (lastReportedActivity > 0 && lastReportedActivity > lastSavedActivity) { + DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); + if (stateData != null) { + DeviceState state = stateData.getState(); + stateData.getState().setLastActivityTime(lastReportedActivity); + pushRuleEngineMessage(stateData, ACTIVITY_EVENT); + save(deviceId, LAST_ACTIVITY_TIME, lastReportedActivity); + deviceLastSavedActivity.put(deviceId, lastReportedActivity); + if (!state.isActive()) { + state.setActive(true); + save(deviceId, ACTIVITY_STATE, state.isActive()); + } } } } @@ -431,6 +441,8 @@ public class DefaultDeviceStateService implements DeviceStateService { Optional address = routingService.resolveById(deviceId); if (!address.isPresent()) { deviceStates.remove(deviceId); + deviceLastReportedActivity.remove(deviceId); + deviceLastSavedActivity.remove(deviceId); Set deviceIds = tenantDevices.get(tenantId); if (deviceIds != null) { deviceIds.remove(deviceId); From d55c374e364d3d596e9dfd106fb65e92bf3be39c Mon Sep 17 00:00:00 2001 From: vlad Date: Fri, 20 Dec 2019 16:16:01 +0200 Subject: [PATCH 18/46] reverted password --- application/src/main/resources/thingsboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index eeeff502ae..c03240e17f 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -384,7 +384,7 @@ spring: driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" username: "${SPRING_DATASOURCE_USERNAME:postgres}" - password: "${SPRING_DATASOURCE_PASSWORD:123456}" + password: "${SPRING_DATASOURCE_PASSWORD:postgres}" hikari: maximumPoolSize: "${SPRING_DATASOURCE_MAXIMUM_POOL_SIZE:50}" From 29a29662e6fc716c1a6742114dbd2bfbaedd0cb7 Mon Sep 17 00:00:00 2001 From: Dmytro Shvaika Date: Mon, 9 Dec 2019 16:27:14 +0200 Subject: [PATCH 19/46] rule-node-ui-changes --- .../public/static/rulenode/rulenode-core-config.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 2ed9e929b1..54159b3feb 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,6 +1,6 @@ -!function(e){function t(i){if(n[i])return n[i].exports;var a=n[i]={exports:{},id:i,loaded:!1};return e[i].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="/static/",t(0)}(function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t))switch(typeof e[t]){case"function":break;case"object":e[t]=function(t){var n=t.slice(1),i=e[t[0]];return function(e,t,a){i.apply(this,[e,t,a].concat(n))}}(e[t]);break;default:e[t]=e[e[t]]}return e}([function(e,t,n){e.exports=n(101)},function(e,t){},1,1,1,1,function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
{{ 'tb.rulenode.create-customer-if-not-exists' | translate }}
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{scope.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
tb.rulenode.alarm-type-required
tb.rulenode.entity-type-pattern-hint
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
{{ 'tb.rulenode.use-message-alarm-data' | translate }}
tb.rulenode.alarm-type-required
tb.rulenode.entity-type-pattern-hint
{{ severity.name | translate}}
tb.rulenode.alarm-severity-required
{{ 'tb.rulenode.propagate' | translate }}
"},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.entity-type-pattern-required
tb.rulenode.entity-type-pattern-hint
tb.rulenode.relation-type-pattern-required
tb.rulenode.relation-type-pattern-hint
{{ 'tb.rulenode.create-entity-if-not-exists' | translate }}
tb.rulenode.create-entity-if-not-exists-hint
{{ 'tb.rulenode.remove-current-relations' | translate }}
tb.rulenode.remove-current-relations-hint
{{ 'tb.rulenode.change-originator-to-related-entity' | translate }}
tb.rulenode.change-originator-to-related-entity-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
{{ 'tb.rulenode.delete-relation-to-specific-entity' | translate }}
tb.rulenode.delete-relation-hint
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.relation-type-pattern-required
tb.rulenode.relation-type-pattern-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
tb.rulenode.message-count-required
tb.rulenode.min-message-count-message
tb.rulenode.period-seconds-required
tb.rulenode.min-period-seconds-message
{{ 'tb.rulenode.test-generator-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.latitude-key-name-required
tb.rulenode.longitude-key-name-required
{{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}
{{ type.name | translate}}
tb.rulenode.circle-center-latitude-required
tb.rulenode.circle-center-longitude-required
tb.rulenode.range-required
{{ type.name | translate}}
tb.rulenode.polygon-definition-required
tb.rulenode.polygon-definition-hint
tb.rulenode.min-inside-duration-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.min-outside-duration-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
'},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.bootstrap-servers-required
tb.rulenode.min-retries-message
tb.rulenode.min-batch-size-bytes-message
tb.rulenode.min-linger-ms-message
tb.rulenode.min-buffer-memory-bytes-message
{{ ackValue }}
tb.rulenode.key-serializer-required
tb.rulenode.value-serializer-required
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-to-string-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.mqtt-topic-pattern-hint
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
tb.rulenode.connect-timeout-required
tb.rulenode.connect-timeout-range
tb.rulenode.connect-timeout-range
{{ \'tb.rulenode.clean-session\' | translate }} {{ \'tb.rulenode.enable-ssl\' | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{credentialsValue.name | translate}}
tb.rulenode.credentials-type-required
tb.rulenode.username-required
tb.rulenode.password-required
'},function(e,t){e.exports="
tb.rulenode.interval-seconds-required
tb.rulenode.min-interval-seconds-message
tb.rulenode.output-timeseries-key-prefix-required
"; -},function(e,t){e.exports='
{{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
tb.rulenode.period-seconds-required
tb.rulenode.min-period-0-seconds-message
tb.rulenode.period-in-seconds-pattern-required
tb.rulenode.period-in-seconds-pattern-hint
tb.rulenode.max-pending-messages-required
tb.rulenode.max-pending-messages-range
tb.rulenode.max-pending-messages-range
'},function(e,t){e.exports="
tb.rulenode.gcp-project-id-required
tb.rulenode.pubsub-topic-name-required
{{ 'action.remove' | translate }} close
tb.rulenode.message-attributes-hint
"},function(e,t){e.exports='
{{ property }}
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
{{ \'tb.rulenode.automatic-recovery\' | translate }}
tb.rulenode.min-connection-timeout-ms-message
tb.rulenode.min-handshake-timeout-ms-message
'},function(e,t){e.exports='
tb.rulenode.endpoint-url-pattern-required
tb.rulenode.endpoint-url-pattern-hint
{{ type }} {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}
tb.rulenode.read-timeout-hint
tb.rulenode.max-parallel-requests-count-hint
tb.rulenode.headers-hint
{{ \'tb.rulenode.use-redis-queue\' | translate }}
{{ \'tb.rulenode.trim-redis-queue\' | translate }}
'},function(e,t){e.exports="
"},function(e,t){e.exports="
tb.rulenode.timeout-required
tb.rulenode.min-timeout-message
"},function(e,t){e.exports='
tb.rulenode.custom-table-name-required
tb.rulenode.custom-table-hint
'},function(e,t){e.exports='
{{ \'tb.rulenode.use-system-smtp-settings\' | translate }}
{{smtpProtocol.toUpperCase()}}
tb.rulenode.smtp-host-required
tb.rulenode.smtp-port-required
tb.rulenode.smtp-port-range
tb.rulenode.smtp-port-range
tb.rulenode.timeout-required
tb.rulenode.min-timeout-msec-message
{{ \'tb.rulenode.enable-tls\' | translate }}
'},function(e,t){e.exports="
tb.rulenode.topic-arn-pattern-required
tb.rulenode.topic-arn-pattern-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
"},function(e,t){e.exports='
{{ type.name | translate }}
tb.rulenode.queue-url-pattern-required
tb.rulenode.queue-url-pattern-hint
tb.rulenode.min-delay-seconds-message
tb.rulenode.max-delay-seconds-message
tb.rulenode.message-attributes-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
'},function(e,t){e.exports="
tb.rulenode.default-ttl-required
tb.rulenode.min-default-ttl-message
"},function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{ (\'relation.search-direction.\' + direction) | translate}}
relation.relation-type
device.device-types
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
{{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}
tb.rulenode.get-latest-value-with-ts-hint
'},function(e,t){e.exports='
{{\'tb.rulenode.entity-details-\'+item.toLowerCase() | translate}} tb.rulenode.no-entity-details-matching {{\'tb.rulenode.entity-details-\'+$chip.toLowerCase() | translate}} {{ \'tb.rulenode.add-to-metadata\' | translate }}
tb.rulenode.add-to-metadata-hint
'},function(e,t){e.exports='
{{ type }}
tb.rulenode.fetch-mode-hint
{{ type }}
tb.rulenode.order-by-hint
tb.rulenode.limit-hint
{{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}
tb.rulenode.use-metadata-interval-patterns-hint
tb.rulenode.start-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.end-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.start-interval-pattern-required
tb.rulenode.start-interval-pattern-hint
tb.rulenode.end-interval-pattern-required
tb.rulenode.end-interval-pattern-hint
'; -},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
{{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}
tb.rulenode.get-latest-value-with-ts-hint
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},31,function(e,t){e.exports='
tb.rulenode.separator-hint
tb.rulenode.separator-hint
{{ \'tb.rulenode.check-all-keys\' | translate }}
tb.rulenode.check-all-keys-hint
'},function(e,t){e.exports="
{{ 'tb.rulenode.check-relation-to-specific-entity' | translate }}
tb.rulenode.check-relation-hint
{{ ('relation.search-direction.' + direction) | translate}}
"},function(e,t){e.exports='
tb.rulenode.latitude-key-name-required
tb.rulenode.longitude-key-name-required
{{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}
{{ type.name | translate}}
tb.rulenode.circle-center-latitude-required
tb.rulenode.circle-center-longitude-required
tb.rulenode.range-required
{{ type.name | translate}}
tb.rulenode.polygon-definition-required
tb.rulenode.polygon-definition-hint
'},function(e,t){e.exports='
{{item}}
tb.rulenode.no-message-types-found
tb.rulenode.no-message-type-matching tb.rulenode.create-new-message-type
{{$chip.name}}
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-filter-function' | translate }}
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-switch-function' | translate }}
"},function(e,t){e.exports='
{{ keyText }} {{ valText }}  
{{keyRequiredText}}
{{valRequiredText}}
{{ \'tb.key-val.remove-entry\' | translate }} close
{{ \'tb.key-val.add-entry\' | translate }} add {{ \'action.add\' | translate }}
'},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
relation.relation-filters
"},function(e,t){e.exports='
{{ source.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-transformer-function' | translate }}
"},function(e,t){e.exports="
tb.rulenode.from-template-required
tb.rulenode.from-template-hint
tb.rulenode.to-template-required
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.subject-template-required
tb.rulenode.subject-template-hint
tb.rulenode.body-template-required
tb.rulenode.body-template-hint
"},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(6),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(7),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(8),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(9),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(10),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(11),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.originator=null,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue,a.configuration.originatorId&&a.configuration.originatorType?a.originator={id:a.configuration.originatorId,entityType:a.configuration.originatorType}:a.originator=null,a.$watch("originator",function(e,t){angular.equals(e,t)||(a.originator?(s.$viewValue.originatorId=a.originator.id,s.$viewValue.originatorType=a.originator.entityType):(s.$viewValue.originatorId=null,s.$viewValue.originatorType=null))},!0)},a.testScript=function(e){var n=angular.copy(a.configuration.jsScript);i.testNodeScript(e,n,"generate",t.instant("tb.rulenode.generator")+"","Generate",["prevMsg","prevMetadata","prevMsgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(1);var r=n(12),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(13),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(74),r=i(a),o=n(52),l=i(o),s=n(57),d=i(s),u=n(54),c=i(u),m=n(53),g=i(m),p=n(61),f=i(p),b=n(68),v=i(b),y=n(69),h=i(y),q=n(67),x=i(q),k=n(60),$=i(k),T=n(72),C=i(T),w=n(73),M=i(w),N=n(66),S=i(N),_=n(62),E=i(_),F=n(71),P=i(F),A=n(64),V=i(A),I=n(63),j=i(I),O=n(51),D=i(O),R=n(75),K=i(R),L=n(56),U=i(L),z=n(55),H=i(z),B=n(70),G=i(B),Y=n(58),Q=i(Y),W=n(65),J=i(W);t.default=angular.module("thingsboard.ruleChain.config.action",[]).directive("tbActionNodeTimeseriesConfig",r.default).directive("tbActionNodeAttributesConfig",l.default).directive("tbActionNodeGeneratorConfig",d.default).directive("tbActionNodeCreateAlarmConfig",c.default).directive("tbActionNodeClearAlarmConfig",g.default).directive("tbActionNodeLogConfig",f.default).directive("tbActionNodeRpcReplyConfig",v.default).directive("tbActionNodeRpcRequestConfig",h.default).directive("tbActionNodeRestApiCallConfig",x.default).directive("tbActionNodeKafkaConfig",$.default).directive("tbActionNodeSnsConfig",C.default).directive("tbActionNodeSqsConfig",M.default).directive("tbActionNodeRabbitMqConfig",S.default).directive("tbActionNodeMqttConfig",E.default).directive("tbActionNodeSendEmailConfig",P.default).directive("tbActionNodeMsgDelayConfig",V.default).directive("tbActionNodeMsgCountConfig",j.default).directive("tbActionNodeAssignToCustomerConfig",D.default).directive("tbActionNodeUnAssignToCustomerConfig",K.default).directive("tbActionNodeDeleteRelationConfig",U.default).directive("tbActionNodeCreateRelationConfig",H.default).directive("tbActionNodeCustomTableConfig",G.default).directive("tbActionNodeGpsGeofencingConfig",Q.default).directive("tbActionNodePubSubConfig",J.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.ackValues=["all","-1","0","1"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(14),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"string",t.instant("tb.rulenode.to-string")+"","ToString",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(15),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$mdExpansionPanel=t,i.ruleNodeTypes=n,i.credentialsTypeChanged=function(){var e=i.configuration.credentials.type;i.configuration.credentials={},i.configuration.credentials.type=e,i.updateValidity()},i.certFileAdded=function(e,t){var n=new FileReader;n.onload=function(n){i.$apply(function(){if(n.target.result){l.$setDirty();var a=n.target.result;a&&a.length>0&&("caCert"==t&&(i.configuration.credentials.caCertFileName=e.name,i.configuration.credentials.caCert=a),"privateKey"==t&&(i.configuration.credentials.privateKeyFileName=e.name,i.configuration.credentials.privateKey=a),"Cert"==t&&(i.configuration.credentials.certFileName=e.name,i.configuration.credentials.cert=a)),i.updateValidity()}})},n.readAsText(e.file)},i.clearCertFile=function(e){l.$setDirty(),"caCert"==e&&(i.configuration.credentials.caCertFileName=null,i.configuration.credentials.caCert=null),"privateKey"==e&&(i.configuration.credentials.privateKeyFileName=null,i.configuration.credentials.privateKey=null),"Cert"==e&&(i.configuration.credentials.certFileName=null,i.configuration.credentials.cert=null),i.updateValidity()},i.updateValidity=function(){var e=!0,t=i.configuration.credentials;t.type==n.mqttCredentialTypes["cert.PEM"].value&&(t.caCert&&t.cert&&t.privateKey||(e=!1)),l.$setValidity("Certs",e)},i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:i}}a.$inject=["$compile","$mdExpansionPanel","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(2);var r=n(16),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(17),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(18),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.serviceAccountFileAdded=function(e){var t=new FileReader;t.onload=function(t){n.$apply(function(){if(t.target.result){r.$setDirty();var i=t.target.result;i&&i.length>0&&(n.configuration.serviceAccountKeyFileName=e.name,n.configuration.serviceAccountKey=i),n.updateValidity()}})},t.readAsText(e.file)},n.clearServiceAccountFile=function(){r.$setDirty(),n.configuration.serviceAccountKeyFileName=null,n.configuration.serviceAccountKey=null,n.updateValidity()},n.updateValidity=function(){var e=!0,t=n.configuration;t.serviceAccountKeyFileName&&t.serviceAccountKey||(e=!1),r.$setValidity("SAKey",e)},n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(19),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}a.$inject=["$compile"], -Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(20),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(21),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(22),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(23),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(24),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.smtpProtocols=["smtp","smtps"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(25),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(26),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(27),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(28),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(29),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(30),o=i(r)},function(e,t){"use strict";function n(e){var t=function(t,n,i,a){n.html("
"),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}n.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(31),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(32),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),n.entityDetailsList=[];for(var s in t.entityDetails){var d=s;n.entityDetailsList.push(d)}r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(33),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s);var d=186;i.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,d],i.ruleNodeTypes=n,i.aggPeriodTimeUnits={},i.aggPeriodTimeUnits.MINUTES=n.timeUnit.MINUTES,i.aggPeriodTimeUnits.HOURS=n.timeUnit.HOURS,i.aggPeriodTimeUnits.DAYS=n.timeUnit.DAYS,i.aggPeriodTimeUnits.MILLISECONDS=n.timeUnit.MILLISECONDS,i.aggPeriodTimeUnits.SECONDS=n.timeUnit.SECONDS,i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{},link:i}}a.$inject=["$compile","$mdConstant","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(34),o=i(r);n(3)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(83),r=i(a),o=n(84),l=i(o),s=n(79),d=i(s),u=n(85),c=i(u),m=n(78),g=i(m),p=n(86),f=i(p),b=n(81),v=i(b),y=n(80),h=i(y);t.default=angular.module("thingsboard.ruleChain.config.enrichment",[]).directive("tbEnrichmentNodeOriginatorAttributesConfig",r.default).directive("tbEnrichmentNodeOriginatorFieldsConfig",l.default).directive("tbEnrichmentNodeDeviceAttributesConfig",d.default).directive("tbEnrichmentNodeRelatedAttributesConfig",c.default).directive("tbEnrichmentNodeCustomerAttributesConfig",g.default).directive("tbEnrichmentNodeTenantAttributesConfig",f.default).directive("tbEnrichmentNodeGetTelemetryFromDatabase",v.default).directive("tbEnrichmentNodeEntityDetailsConfig",h.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(35),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(36),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(37),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(38),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(39),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(40),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(41),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(93),r=i(a),o=n(91),l=i(o),s=n(94),d=i(s),u=n(88),c=i(u),m=n(92),g=i(m),p=n(87),f=i(p),b=n(89),v=i(b);t.default=angular.module("thingsboard.ruleChain.config.filter",[]).directive("tbFilterNodeScriptConfig",r.default).directive("tbFilterNodeMessageTypeConfig",l.default).directive("tbFilterNodeSwitchConfig",d.default).directive("tbFilterNodeCheckRelationConfig",c.default).directive("tbFilterNodeOriginatorTypeConfig",g.default).directive("tbFilterNodeCheckMessageConfig",f.default).directive("tbFilterNodeGpsGeofencingConfig",v.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){function s(){if(l.$viewValue){for(var e=[],t=0;t-1&&t.kvList.splice(e,1)}function l(){t.kvList||(t.kvList=[]),t.kvList.push({key:"",value:""})}function s(){var e={};t.kvList.forEach(function(t){t.key&&(e[t.key]=t.value)}),a.$setViewValue(e),d()}function d(){var e=!0;t.required&&!t.kvList.length&&(e=!1),a.$setValidity("kvMap",e)}var u=o.default;n.html(u),t.ngModelCtrl=a,t.removeKeyVal=r,t.addKeyVal=l,t.kvList=[],t.$watch("query",function(e,n){angular.equals(e,n)||a.$setViewValue(t.query)}),a.$render=function(){if(a.$viewValue){var e=a.$viewValue;t.kvList.length=0;for(var n in e)t.kvList.push({key:n,value:e[n]})}t.$watch("kvList",function(e,t){angular.equals(e,t)||s()},!0),d()},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",disabled:"=ngDisabled",requiredText:"=",keyText:"=",keyRequiredText:"=",valText:"=",valRequiredText:"="},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(46),o=i(r);n(5)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(47),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(48),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(97),r=i(a),o=n(99),l=i(o),s=n(100),d=i(s);t.default=angular.module("thingsboard.ruleChain.config.transform",[]).directive("tbTransformationNodeChangeOriginatorConfig",r.default).directive("tbTransformationNodeScriptConfig",l.default).directive("tbTransformationNodeToEmailConfig",d.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"update",t.instant("tb.rulenode.transformer")+"","Transform",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(49),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(50),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(104),r=i(a),o=n(90),l=i(o),s=n(82),d=i(s),u=n(98),c=i(u),m=n(59),g=i(m),p=n(77),f=i(p),b=n(96),v=i(b),y=n(76),h=i(y),q=n(95),x=i(q),k=n(103),$=i(k);t.default=angular.module("thingsboard.ruleChain.config",[r.default,l.default,d.default,c.default,g.default]).directive("tbNodeEmptyConfig",f.default).directive("tbRelationsQueryConfig",v.default).directive("tbDeviceRelationsQueryConfig",h.default).directive("tbKvMapConfig",x.default).config($.default).name},function(e,t){"use strict";function n(e){var t={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-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","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-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","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","latest-timeseries":"Latest timeseries","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-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","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 metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","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",propagate:"Propagate",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","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","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","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","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 ${metaKeyName} in header/value fields to substitute variables from metadata",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","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata","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","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","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","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata", -"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 ${metaKeyName} in name/value fields to substitute variables from metadata","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","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","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"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 metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","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","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","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","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-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-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"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}};e.translations("en_US",t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){(0,o.default)(e)}a.$inject=["$translateProvider"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(102),o=i(r)},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=angular.module("thingsboard.ruleChain.config.types",[]).constant("ruleNodeTypes",{originatorSource:{CUSTOMER:{name:"tb.rulenode.originator-customer",value:"CUSTOMER"},TENANT:{name:"tb.rulenode.originator-tenant",value:"TENANT"},RELATED:{name:"tb.rulenode.originator-related",value:"RELATED"},ALARM_ORIGINATOR:{name:"tb.rulenode.originator-alarm-originator",value:"ALARM_ORIGINATOR"}},fetchModeType:["FIRST","LAST","ALL"],samplingOrder:["ASC","DESC"],httpRequestType:["GET","POST","PUT","DELETE"],entityDetails:{TITLE:{name:"tb.rulenode.entity-details-title",value:"TITLE"},COUNTRY:{name:"tb.rulenode.entity-details-country",value:"COUNTRY"},STATE:{name:"tb.rulenode.entity-details-state",value:"STATE"},ZIP:{name:"tb.rulenode.entity-details-zip",value:"ZIP"},ADDRESS:{name:"tb.rulenode.entity-details-address",value:"ADDRESS"},ADDRESS2:{name:"tb.rulenode.entity-details-address2",value:"ADDRESS2"},PHONE:{name:"tb.rulenode.entity-details-phone",value:"PHONE"},EMAIL:{name:"tb.rulenode.entity-details-email",value:"EMAIL"},ADDITIONAL_INFO:{name:"tb.rulenode.entity-details-additional_info",value:"ADDITIONAL_INFO"}},sqsQueueType:{STANDARD:{name:"tb.rulenode.sqs-queue-standard",value:"STANDARD"},FIFO:{name:"tb.rulenode.sqs-queue-fifo",value:"FIFO"}},perimeterType:{CIRCLE:{name:"tb.rulenode.perimeter-circle",value:"CIRCLE"},POLYGON:{name:"tb.rulenode.perimeter-polygon",value:"POLYGON"}},timeUnit:{MILLISECONDS:{value:"MILLISECONDS",name:"tb.rulenode.time-unit-milliseconds"},SECONDS:{value:"SECONDS",name:"tb.rulenode.time-unit-seconds"},MINUTES:{value:"MINUTES",name:"tb.rulenode.time-unit-minutes"},HOURS:{value:"HOURS",name:"tb.rulenode.time-unit-hours"},DAYS:{value:"DAYS",name:"tb.rulenode.time-unit-days"}},rangeUnit:{METER:{value:"METER",name:"tb.rulenode.range-unit-meter"},KILOMETER:{value:"KILOMETER",name:"tb.rulenode.range-unit-kilometer"},FOOT:{value:"FOOT",name:"tb.rulenode.range-unit-foot"},MILE:{value:"MILE",name:"tb.rulenode.range-unit-mile"},NAUTICAL_MILE:{value:"NAUTICAL_MILE",name:"tb.rulenode.range-unit-nautical-mile"}},mqttCredentialTypes:{anonymous:{value:"anonymous",name:"tb.rulenode.credentials-anonymous"},basic:{value:"basic",name:"tb.rulenode.credentials-basic"},"cert.PEM":{value:"cert.PEM",name:"tb.rulenode.credentials-pem"}}}).name}])); +!function(e){function t(i){if(n[i])return n[i].exports;var a=n[i]={exports:{},id:i,loaded:!1};return e[i].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="/static/",t(0)}(function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t))switch(typeof e[t]){case"function":break;case"object":e[t]=function(t){var n=t.slice(1),i=e[t[0]];return function(e,t,a){i.apply(this,[e,t,a].concat(n))}}(e[t]);break;default:e[t]=e[e[t]]}return e}([function(e,t,n){e.exports=n(101)},function(e,t){},1,1,1,1,function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
{{ 'tb.rulenode.create-customer-if-not-exists' | translate }}
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{scope.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
tb.rulenode.alarm-type-required
tb.rulenode.entity-type-pattern-hint
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
{{ 'tb.rulenode.use-message-alarm-data' | translate }}
tb.rulenode.alarm-type-required
tb.rulenode.entity-type-pattern-hint
{{ severity.name | translate}}
tb.rulenode.alarm-severity-required
{{ 'tb.rulenode.propagate' | translate }}
tb.rulenode.relation-types-list-hint
"},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.entity-type-pattern-required
tb.rulenode.entity-type-pattern-hint
tb.rulenode.relation-type-pattern-required
tb.rulenode.relation-type-pattern-hint
{{ 'tb.rulenode.create-entity-if-not-exists' | translate }}
tb.rulenode.create-entity-if-not-exists-hint
{{ 'tb.rulenode.remove-current-relations' | translate }}
tb.rulenode.remove-current-relations-hint
{{ 'tb.rulenode.change-originator-to-related-entity' | translate }}
tb.rulenode.change-originator-to-related-entity-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
{{ 'tb.rulenode.delete-relation-to-specific-entity' | translate }}
tb.rulenode.delete-relation-hint
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.relation-type-pattern-required
tb.rulenode.relation-type-pattern-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
tb.rulenode.message-count-required
tb.rulenode.min-message-count-message
tb.rulenode.period-seconds-required
tb.rulenode.min-period-seconds-message
{{ 'tb.rulenode.test-generator-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.latitude-key-name-required
tb.rulenode.longitude-key-name-required
{{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}
{{ type.name | translate}}
tb.rulenode.circle-center-latitude-required
tb.rulenode.circle-center-longitude-required
tb.rulenode.range-required
{{ type.name | translate}}
tb.rulenode.polygon-definition-required
tb.rulenode.polygon-definition-hint
tb.rulenode.min-inside-duration-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.min-outside-duration-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
'},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.bootstrap-servers-required
tb.rulenode.min-retries-message
tb.rulenode.min-batch-size-bytes-message
tb.rulenode.min-linger-ms-message
tb.rulenode.min-buffer-memory-bytes-message
{{ ackValue }}
tb.rulenode.key-serializer-required
tb.rulenode.value-serializer-required
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-to-string-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.mqtt-topic-pattern-hint
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
tb.rulenode.connect-timeout-required
tb.rulenode.connect-timeout-range
tb.rulenode.connect-timeout-range
{{ \'tb.rulenode.clean-session\' | translate }} {{ \'tb.rulenode.enable-ssl\' | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{credentialsValue.name | translate}}
tb.rulenode.credentials-type-required
tb.rulenode.username-required
tb.rulenode.password-required
'; +},function(e,t){e.exports="
tb.rulenode.interval-seconds-required
tb.rulenode.min-interval-seconds-message
tb.rulenode.output-timeseries-key-prefix-required
"},function(e,t){e.exports='
{{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
tb.rulenode.period-seconds-required
tb.rulenode.min-period-0-seconds-message
tb.rulenode.period-in-seconds-pattern-required
tb.rulenode.period-in-seconds-pattern-hint
tb.rulenode.max-pending-messages-required
tb.rulenode.max-pending-messages-range
tb.rulenode.max-pending-messages-range
'},function(e,t){e.exports="
tb.rulenode.gcp-project-id-required
tb.rulenode.pubsub-topic-name-required
{{ 'action.remove' | translate }} close
tb.rulenode.message-attributes-hint
"},function(e,t){e.exports='
{{ property }}
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
{{ \'tb.rulenode.automatic-recovery\' | translate }}
tb.rulenode.min-connection-timeout-ms-message
tb.rulenode.min-handshake-timeout-ms-message
'},function(e,t){e.exports='
tb.rulenode.endpoint-url-pattern-required
tb.rulenode.endpoint-url-pattern-hint
{{ type }} {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}
tb.rulenode.headers-hint
{{ \'tb.rulenode.use-redis-queue\' | translate }}
{{ \'tb.rulenode.trim-redis-queue\' | translate }}
'},function(e,t){e.exports="
"},function(e,t){e.exports="
tb.rulenode.timeout-required
tb.rulenode.min-timeout-message
"},function(e,t){e.exports='
tb.rulenode.custom-table-name-required
tb.rulenode.custom-table-hint
'},function(e,t){e.exports='
{{ \'tb.rulenode.use-system-smtp-settings\' | translate }}
{{smtpProtocol.toUpperCase()}}
tb.rulenode.smtp-host-required
tb.rulenode.smtp-port-required
tb.rulenode.smtp-port-range
tb.rulenode.smtp-port-range
tb.rulenode.timeout-required
tb.rulenode.min-timeout-msec-message
{{ \'tb.rulenode.enable-tls\' | translate }}
'},function(e,t){e.exports="
tb.rulenode.topic-arn-pattern-required
tb.rulenode.topic-arn-pattern-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
"},function(e,t){e.exports='
{{ type.name | translate }}
tb.rulenode.queue-url-pattern-required
tb.rulenode.queue-url-pattern-hint
tb.rulenode.min-delay-seconds-message
tb.rulenode.max-delay-seconds-message
tb.rulenode.message-attributes-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
'},function(e,t){e.exports="
tb.rulenode.default-ttl-required
tb.rulenode.min-default-ttl-message
"},function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{ (\'relation.search-direction.\' + direction) | translate}}
relation.relation-type
device.device-types
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
'},function(e,t){e.exports='
{{\'tb.rulenode.entity-details-\'+item.toLowerCase() | translate}} tb.rulenode.no-entity-details-matching {{\'tb.rulenode.entity-details-\'+$chip.toLowerCase() | translate}} {{ \'tb.rulenode.add-to-metadata\' | translate }}
tb.rulenode.add-to-metadata-hint
'},function(e,t){e.exports='
{{ type }}
tb.rulenode.fetch-mode-hint
{{ type }}
tb.rulenode.order-by-hint
{{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}
tb.rulenode.use-metadata-interval-patterns-hint
tb.rulenode.start-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.end-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.start-interval-pattern-required
tb.rulenode.start-interval-pattern-hint
tb.rulenode.end-interval-pattern-required
tb.rulenode.end-interval-pattern-hint
'},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
'; +},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},31,function(e,t){e.exports='
tb.rulenode.separator-hint
tb.rulenode.separator-hint
{{ \'tb.rulenode.check-all-keys\' | translate }}
tb.rulenode.check-all-keys-hint
'},function(e,t){e.exports="
{{ 'tb.rulenode.check-relation-to-specific-entity' | translate }}
tb.rulenode.check-relation-hint
{{ ('relation.search-direction.' + direction) | translate}}
"},function(e,t){e.exports='
tb.rulenode.latitude-key-name-required
tb.rulenode.longitude-key-name-required
{{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}
{{ type.name | translate}}
tb.rulenode.circle-center-latitude-required
tb.rulenode.circle-center-longitude-required
tb.rulenode.range-required
{{ type.name | translate}}
tb.rulenode.polygon-definition-required
tb.rulenode.polygon-definition-hint
'},function(e,t){e.exports='
{{item}}
tb.rulenode.no-message-types-found
tb.rulenode.no-message-type-matching tb.rulenode.create-new-message-type
{{$chip.name}}
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-filter-function' | translate }}
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-switch-function' | translate }}
"},function(e,t){e.exports='
{{ keyText }} {{ valText }}  
{{keyRequiredText}}
{{valRequiredText}}
{{ \'tb.key-val.remove-entry\' | translate }} close
{{ \'tb.key-val.add-entry\' | translate }} add {{ \'action.add\' | translate }}
'},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
relation.relation-filters
"},function(e,t){e.exports='
{{ source.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-transformer-function' | translate }}
"},function(e,t){e.exports="
tb.rulenode.from-template-required
tb.rulenode.from-template-hint
tb.rulenode.to-template-required
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.subject-template-required
tb.rulenode.subject-template-hint
tb.rulenode.body-template-required
tb.rulenode.body-template-hint
"},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(6),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(7),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(8),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue,a.configuration.hasOwnProperty("relationTypes")||(a.configuration.relationTypes=[])},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(9),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(10),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(11),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.originator=null,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue,a.configuration.originatorId&&a.configuration.originatorType?a.originator={id:a.configuration.originatorId,entityType:a.configuration.originatorType}:a.originator=null,a.$watch("originator",function(e,t){angular.equals(e,t)||(a.originator?(s.$viewValue.originatorId=a.originator.id,s.$viewValue.originatorType=a.originator.entityType):(s.$viewValue.originatorId=null,s.$viewValue.originatorType=null))},!0)},a.testScript=function(e){var n=angular.copy(a.configuration.jsScript);i.testNodeScript(e,n,"generate",t.instant("tb.rulenode.generator")+"","Generate",["prevMsg","prevMetadata","prevMsgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(1);var r=n(12),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(13),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(74),r=i(a),o=n(52),l=i(o),s=n(57),d=i(s),u=n(54),c=i(u),m=n(53),g=i(m),p=n(61),f=i(p),b=n(68),v=i(b),y=n(69),h=i(y),q=n(67),x=i(q),$=n(60),k=i($),T=n(72),C=i(T),w=n(73),M=i(w),N=n(66),S=i(N),_=n(62),E=i(_),P=n(71),F=i(P),A=n(64),V=i(A),I=n(63),j=i(I),O=n(51),D=i(O),R=n(75),K=i(R),L=n(56),U=i(L),z=n(55),B=i(z),H=n(70),G=i(H),Y=n(58),Q=i(Y),J=n(65),W=i(J);t.default=angular.module("thingsboard.ruleChain.config.action",[]).directive("tbActionNodeTimeseriesConfig",r.default).directive("tbActionNodeAttributesConfig",l.default).directive("tbActionNodeGeneratorConfig",d.default).directive("tbActionNodeCreateAlarmConfig",c.default).directive("tbActionNodeClearAlarmConfig",g.default).directive("tbActionNodeLogConfig",f.default).directive("tbActionNodeRpcReplyConfig",v.default).directive("tbActionNodeRpcRequestConfig",h.default).directive("tbActionNodeRestApiCallConfig",x.default).directive("tbActionNodeKafkaConfig",k.default).directive("tbActionNodeSnsConfig",C.default).directive("tbActionNodeSqsConfig",M.default).directive("tbActionNodeRabbitMqConfig",S.default).directive("tbActionNodeMqttConfig",E.default).directive("tbActionNodeSendEmailConfig",F.default).directive("tbActionNodeMsgDelayConfig",V.default).directive("tbActionNodeMsgCountConfig",j.default).directive("tbActionNodeAssignToCustomerConfig",D.default).directive("tbActionNodeUnAssignToCustomerConfig",K.default).directive("tbActionNodeDeleteRelationConfig",U.default).directive("tbActionNodeCreateRelationConfig",B.default).directive("tbActionNodeCustomTableConfig",G.default).directive("tbActionNodeGpsGeofencingConfig",Q.default).directive("tbActionNodePubSubConfig",W.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.ackValues=["all","-1","0","1"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(14),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"string",t.instant("tb.rulenode.to-string")+"","ToString",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(15),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$mdExpansionPanel=t,i.ruleNodeTypes=n,i.credentialsTypeChanged=function(){var e=i.configuration.credentials.type;i.configuration.credentials={},i.configuration.credentials.type=e,i.updateValidity()},i.certFileAdded=function(e,t){var n=new FileReader;n.onload=function(n){i.$apply(function(){if(n.target.result){l.$setDirty();var a=n.target.result;a&&a.length>0&&("caCert"==t&&(i.configuration.credentials.caCertFileName=e.name,i.configuration.credentials.caCert=a),"privateKey"==t&&(i.configuration.credentials.privateKeyFileName=e.name,i.configuration.credentials.privateKey=a),"Cert"==t&&(i.configuration.credentials.certFileName=e.name,i.configuration.credentials.cert=a)),i.updateValidity()}})},n.readAsText(e.file)},i.clearCertFile=function(e){l.$setDirty(),"caCert"==e&&(i.configuration.credentials.caCertFileName=null,i.configuration.credentials.caCert=null),"privateKey"==e&&(i.configuration.credentials.privateKeyFileName=null,i.configuration.credentials.privateKey=null),"Cert"==e&&(i.configuration.credentials.certFileName=null,i.configuration.credentials.cert=null),i.updateValidity()},i.updateValidity=function(){var e=!0,t=i.configuration.credentials;t.type==n.mqttCredentialTypes["cert.PEM"].value&&(t.caCert&&t.cert&&t.privateKey||(e=!1)),l.$setValidity("Certs",e)},i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:i}}a.$inject=["$compile","$mdExpansionPanel","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(2);var r=n(16),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(17),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(18),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.serviceAccountFileAdded=function(e){var t=new FileReader;t.onload=function(t){n.$apply(function(){if(t.target.result){r.$setDirty();var i=t.target.result;i&&i.length>0&&(n.configuration.serviceAccountKeyFileName=e.name,n.configuration.serviceAccountKey=i),n.updateValidity()}})},t.readAsText(e.file)},n.clearServiceAccountFile=function(){r.$setDirty(),n.configuration.serviceAccountKeyFileName=null,n.configuration.serviceAccountKey=null,n.updateValidity()},n.updateValidity=function(){var e=!0,t=n.configuration;t.serviceAccountKeyFileName&&t.serviceAccountKey||(e=!1),r.$setValidity("SAKey",e)},n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(19),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(20),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(21),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(22),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(23),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue; +},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(24),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.smtpProtocols=["smtp","smtps"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(25),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(26),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(27),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(28),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(29),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(30),o=i(r)},function(e,t){"use strict";function n(e){var t=function(t,n,i,a){n.html("
"),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}n.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(31),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(32),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),n.entityDetailsList=[];for(var s in t.entityDetails){var d=s;n.entityDetailsList.push(d)}r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(33),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s);var d=186;i.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,d],i.ruleNodeTypes=n,i.aggPeriodTimeUnits={},i.aggPeriodTimeUnits.MINUTES=n.timeUnit.MINUTES,i.aggPeriodTimeUnits.HOURS=n.timeUnit.HOURS,i.aggPeriodTimeUnits.DAYS=n.timeUnit.DAYS,i.aggPeriodTimeUnits.MILLISECONDS=n.timeUnit.MILLISECONDS,i.aggPeriodTimeUnits.SECONDS=n.timeUnit.SECONDS,i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{},link:i}}a.$inject=["$compile","$mdConstant","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(34),o=i(r);n(3)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(83),r=i(a),o=n(84),l=i(o),s=n(79),d=i(s),u=n(85),c=i(u),m=n(78),g=i(m),p=n(86),f=i(p),b=n(81),v=i(b),y=n(80),h=i(y);t.default=angular.module("thingsboard.ruleChain.config.enrichment",[]).directive("tbEnrichmentNodeOriginatorAttributesConfig",r.default).directive("tbEnrichmentNodeOriginatorFieldsConfig",l.default).directive("tbEnrichmentNodeDeviceAttributesConfig",d.default).directive("tbEnrichmentNodeRelatedAttributesConfig",c.default).directive("tbEnrichmentNodeCustomerAttributesConfig",g.default).directive("tbEnrichmentNodeTenantAttributesConfig",f.default).directive("tbEnrichmentNodeGetTelemetryFromDatabase",v.default).directive("tbEnrichmentNodeEntityDetailsConfig",h.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(35),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(36),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(37),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(38),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(39),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(40),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(41),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(93),r=i(a),o=n(91),l=i(o),s=n(94),d=i(s),u=n(88),c=i(u),m=n(92),g=i(m),p=n(87),f=i(p),b=n(89),v=i(b);t.default=angular.module("thingsboard.ruleChain.config.filter",[]).directive("tbFilterNodeScriptConfig",r.default).directive("tbFilterNodeMessageTypeConfig",l.default).directive("tbFilterNodeSwitchConfig",d.default).directive("tbFilterNodeCheckRelationConfig",c.default).directive("tbFilterNodeOriginatorTypeConfig",g.default).directive("tbFilterNodeCheckMessageConfig",f.default).directive("tbFilterNodeGpsGeofencingConfig",v.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){function s(){if(l.$viewValue){for(var e=[],t=0;t-1&&t.kvList.splice(e,1)}function l(){t.kvList||(t.kvList=[]),t.kvList.push({key:"",value:""})}function s(){var e={};t.kvList.forEach(function(t){t.key&&(e[t.key]=t.value)}),a.$setViewValue(e),d()}function d(){var e=!0;t.required&&!t.kvList.length&&(e=!1),a.$setValidity("kvMap",e)}var u=o.default;n.html(u),t.ngModelCtrl=a,t.removeKeyVal=r,t.addKeyVal=l,t.kvList=[],t.$watch("query",function(e,n){angular.equals(e,n)||a.$setViewValue(t.query)}),a.$render=function(){if(a.$viewValue){var e=a.$viewValue;t.kvList.length=0;for(var n in e)t.kvList.push({key:n,value:e[n]})}t.$watch("kvList",function(e,t){angular.equals(e,t)||s()},!0),d()},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",disabled:"=ngDisabled",requiredText:"=",keyText:"=",keyRequiredText:"=",valText:"=",valRequiredText:"="},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(46),o=i(r);n(5)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(47),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(48),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(97),r=i(a),o=n(99),l=i(o),s=n(100),d=i(s);t.default=angular.module("thingsboard.ruleChain.config.transform",[]).directive("tbTransformationNodeChangeOriginatorConfig",r.default).directive("tbTransformationNodeScriptConfig",l.default).directive("tbTransformationNodeToEmailConfig",d.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"update",t.instant("tb.rulenode.transformer")+"","Transform",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(49),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(50),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(104),r=i(a),o=n(90),l=i(o),s=n(82),d=i(s),u=n(98),c=i(u),m=n(59),g=i(m),p=n(77),f=i(p),b=n(96),v=i(b),y=n(76),h=i(y),q=n(95),x=i(q),$=n(103),k=i($);t.default=angular.module("thingsboard.ruleChain.config",[r.default,l.default,d.default,c.default,g.default]).directive("tbNodeEmptyConfig",f.default).directive("tbRelationsQueryConfig",v.default).directive("tbDeviceRelationsQueryConfig",h.default).directive("tbKvMapConfig",x.default).config(k.default).name},function(e,t){"use strict";function n(e){var t={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-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","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-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","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.","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","latest-timeseries":"Latest timeseries","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-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","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 metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","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",propagate:"Propagate",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","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","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","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",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","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata","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","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","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","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","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 ${metaKeyName} in name/value fields to substitute variables from metadata","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","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","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"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 metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","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","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","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","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-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-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".',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}};e.translations("en_US",t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){(0,o.default)(e)}a.$inject=["$translateProvider"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(102),o=i(r)},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=angular.module("thingsboard.ruleChain.config.types",[]).constant("ruleNodeTypes",{originatorSource:{CUSTOMER:{name:"tb.rulenode.originator-customer",value:"CUSTOMER"},TENANT:{name:"tb.rulenode.originator-tenant",value:"TENANT"},RELATED:{name:"tb.rulenode.originator-related",value:"RELATED"},ALARM_ORIGINATOR:{name:"tb.rulenode.originator-alarm-originator",value:"ALARM_ORIGINATOR"}},fetchModeType:["FIRST","LAST","ALL"],samplingOrder:["ASC","DESC"],httpRequestType:["GET","POST","PUT","DELETE"],entityDetails:{TITLE:{name:"tb.rulenode.entity-details-title",value:"TITLE"},COUNTRY:{name:"tb.rulenode.entity-details-country",value:"COUNTRY"},STATE:{name:"tb.rulenode.entity-details-state",value:"STATE"},ZIP:{name:"tb.rulenode.entity-details-zip",value:"ZIP"},ADDRESS:{name:"tb.rulenode.entity-details-address",value:"ADDRESS"},ADDRESS2:{name:"tb.rulenode.entity-details-address2",value:"ADDRESS2"},PHONE:{name:"tb.rulenode.entity-details-phone",value:"PHONE"},EMAIL:{name:"tb.rulenode.entity-details-email",value:"EMAIL"},ADDITIONAL_INFO:{name:"tb.rulenode.entity-details-additional_info",value:"ADDITIONAL_INFO"}},sqsQueueType:{STANDARD:{name:"tb.rulenode.sqs-queue-standard",value:"STANDARD"},FIFO:{name:"tb.rulenode.sqs-queue-fifo",value:"FIFO"}},perimeterType:{CIRCLE:{name:"tb.rulenode.perimeter-circle",value:"CIRCLE"},POLYGON:{name:"tb.rulenode.perimeter-polygon",value:"POLYGON"}},timeUnit:{MILLISECONDS:{value:"MILLISECONDS",name:"tb.rulenode.time-unit-milliseconds"},SECONDS:{value:"SECONDS",name:"tb.rulenode.time-unit-seconds"},MINUTES:{value:"MINUTES",name:"tb.rulenode.time-unit-minutes"},HOURS:{value:"HOURS",name:"tb.rulenode.time-unit-hours"},DAYS:{value:"DAYS",name:"tb.rulenode.time-unit-days"}},rangeUnit:{METER:{value:"METER",name:"tb.rulenode.range-unit-meter"},KILOMETER:{value:"KILOMETER",name:"tb.rulenode.range-unit-kilometer"},FOOT:{value:"FOOT",name:"tb.rulenode.range-unit-foot"},MILE:{value:"MILE",name:"tb.rulenode.range-unit-mile"},NAUTICAL_MILE:{value:"NAUTICAL_MILE",name:"tb.rulenode.range-unit-nautical-mile"}},mqttCredentialTypes:{anonymous:{value:"anonymous",name:"tb.rulenode.credentials-anonymous"},basic:{value:"basic",name:"tb.rulenode.credentials-basic"},"cert.PEM":{value:"cert.PEM",name:"tb.rulenode.credentials-pem"}}}).name}])); //# sourceMappingURL=rulenode-core-config.js.map \ No newline at end of file From 1b4ef0c9fa221392aebad4ada776512e2a79492f Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Fri, 20 Dec 2019 17:42:07 +0200 Subject: [PATCH 20/46] Latest UI --- .../public/static/rulenode/rulenode-core-config.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 54159b3feb..0358f23448 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,6 +1,6 @@ !function(e){function t(i){if(n[i])return n[i].exports;var a=n[i]={exports:{},id:i,loaded:!1};return e[i].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="/static/",t(0)}(function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t))switch(typeof e[t]){case"function":break;case"object":e[t]=function(t){var n=t.slice(1),i=e[t[0]];return function(e,t,a){i.apply(this,[e,t,a].concat(n))}}(e[t]);break;default:e[t]=e[e[t]]}return e}([function(e,t,n){e.exports=n(101)},function(e,t){},1,1,1,1,function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
{{ 'tb.rulenode.create-customer-if-not-exists' | translate }}
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{scope.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
tb.rulenode.alarm-type-required
tb.rulenode.entity-type-pattern-hint
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
{{ 'tb.rulenode.use-message-alarm-data' | translate }}
tb.rulenode.alarm-type-required
tb.rulenode.entity-type-pattern-hint
{{ severity.name | translate}}
tb.rulenode.alarm-severity-required
{{ 'tb.rulenode.propagate' | translate }}
tb.rulenode.relation-types-list-hint
"},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.entity-type-pattern-required
tb.rulenode.entity-type-pattern-hint
tb.rulenode.relation-type-pattern-required
tb.rulenode.relation-type-pattern-hint
{{ 'tb.rulenode.create-entity-if-not-exists' | translate }}
tb.rulenode.create-entity-if-not-exists-hint
{{ 'tb.rulenode.remove-current-relations' | translate }}
tb.rulenode.remove-current-relations-hint
{{ 'tb.rulenode.change-originator-to-related-entity' | translate }}
tb.rulenode.change-originator-to-related-entity-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
{{ 'tb.rulenode.delete-relation-to-specific-entity' | translate }}
tb.rulenode.delete-relation-hint
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.relation-type-pattern-required
tb.rulenode.relation-type-pattern-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
tb.rulenode.message-count-required
tb.rulenode.min-message-count-message
tb.rulenode.period-seconds-required
tb.rulenode.min-period-seconds-message
{{ 'tb.rulenode.test-generator-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.latitude-key-name-required
tb.rulenode.longitude-key-name-required
{{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}
{{ type.name | translate}}
tb.rulenode.circle-center-latitude-required
tb.rulenode.circle-center-longitude-required
tb.rulenode.range-required
{{ type.name | translate}}
tb.rulenode.polygon-definition-required
tb.rulenode.polygon-definition-hint
tb.rulenode.min-inside-duration-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.min-outside-duration-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
'},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.bootstrap-servers-required
tb.rulenode.min-retries-message
tb.rulenode.min-batch-size-bytes-message
tb.rulenode.min-linger-ms-message
tb.rulenode.min-buffer-memory-bytes-message
{{ ackValue }}
tb.rulenode.key-serializer-required
tb.rulenode.value-serializer-required
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-to-string-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.mqtt-topic-pattern-hint
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
tb.rulenode.connect-timeout-required
tb.rulenode.connect-timeout-range
tb.rulenode.connect-timeout-range
{{ \'tb.rulenode.clean-session\' | translate }} {{ \'tb.rulenode.enable-ssl\' | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{credentialsValue.name | translate}}
tb.rulenode.credentials-type-required
tb.rulenode.username-required
tb.rulenode.password-required
'; -},function(e,t){e.exports="
tb.rulenode.interval-seconds-required
tb.rulenode.min-interval-seconds-message
tb.rulenode.output-timeseries-key-prefix-required
"},function(e,t){e.exports='
{{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
tb.rulenode.period-seconds-required
tb.rulenode.min-period-0-seconds-message
tb.rulenode.period-in-seconds-pattern-required
tb.rulenode.period-in-seconds-pattern-hint
tb.rulenode.max-pending-messages-required
tb.rulenode.max-pending-messages-range
tb.rulenode.max-pending-messages-range
'},function(e,t){e.exports="
tb.rulenode.gcp-project-id-required
tb.rulenode.pubsub-topic-name-required
{{ 'action.remove' | translate }} close
tb.rulenode.message-attributes-hint
"},function(e,t){e.exports='
{{ property }}
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
{{ \'tb.rulenode.automatic-recovery\' | translate }}
tb.rulenode.min-connection-timeout-ms-message
tb.rulenode.min-handshake-timeout-ms-message
'},function(e,t){e.exports='
tb.rulenode.endpoint-url-pattern-required
tb.rulenode.endpoint-url-pattern-hint
{{ type }} {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}
tb.rulenode.headers-hint
{{ \'tb.rulenode.use-redis-queue\' | translate }}
{{ \'tb.rulenode.trim-redis-queue\' | translate }}
'},function(e,t){e.exports="
"},function(e,t){e.exports="
tb.rulenode.timeout-required
tb.rulenode.min-timeout-message
"},function(e,t){e.exports='
tb.rulenode.custom-table-name-required
tb.rulenode.custom-table-hint
'},function(e,t){e.exports='
{{ \'tb.rulenode.use-system-smtp-settings\' | translate }}
{{smtpProtocol.toUpperCase()}}
tb.rulenode.smtp-host-required
tb.rulenode.smtp-port-required
tb.rulenode.smtp-port-range
tb.rulenode.smtp-port-range
tb.rulenode.timeout-required
tb.rulenode.min-timeout-msec-message
{{ \'tb.rulenode.enable-tls\' | translate }}
'},function(e,t){e.exports="
tb.rulenode.topic-arn-pattern-required
tb.rulenode.topic-arn-pattern-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
"},function(e,t){e.exports='
{{ type.name | translate }}
tb.rulenode.queue-url-pattern-required
tb.rulenode.queue-url-pattern-hint
tb.rulenode.min-delay-seconds-message
tb.rulenode.max-delay-seconds-message
tb.rulenode.message-attributes-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
'},function(e,t){e.exports="
tb.rulenode.default-ttl-required
tb.rulenode.min-default-ttl-message
"},function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{ (\'relation.search-direction.\' + direction) | translate}}
relation.relation-type
device.device-types
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
'},function(e,t){e.exports='
{{\'tb.rulenode.entity-details-\'+item.toLowerCase() | translate}} tb.rulenode.no-entity-details-matching {{\'tb.rulenode.entity-details-\'+$chip.toLowerCase() | translate}} {{ \'tb.rulenode.add-to-metadata\' | translate }}
tb.rulenode.add-to-metadata-hint
'},function(e,t){e.exports='
{{ type }}
tb.rulenode.fetch-mode-hint
{{ type }}
tb.rulenode.order-by-hint
{{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}
tb.rulenode.use-metadata-interval-patterns-hint
tb.rulenode.start-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.end-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.start-interval-pattern-required
tb.rulenode.start-interval-pattern-hint
tb.rulenode.end-interval-pattern-required
tb.rulenode.end-interval-pattern-hint
'},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
'; -},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},31,function(e,t){e.exports='
tb.rulenode.separator-hint
tb.rulenode.separator-hint
{{ \'tb.rulenode.check-all-keys\' | translate }}
tb.rulenode.check-all-keys-hint
'},function(e,t){e.exports="
{{ 'tb.rulenode.check-relation-to-specific-entity' | translate }}
tb.rulenode.check-relation-hint
{{ ('relation.search-direction.' + direction) | translate}}
"},function(e,t){e.exports='
tb.rulenode.latitude-key-name-required
tb.rulenode.longitude-key-name-required
{{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}
{{ type.name | translate}}
tb.rulenode.circle-center-latitude-required
tb.rulenode.circle-center-longitude-required
tb.rulenode.range-required
{{ type.name | translate}}
tb.rulenode.polygon-definition-required
tb.rulenode.polygon-definition-hint
'},function(e,t){e.exports='
{{item}}
tb.rulenode.no-message-types-found
tb.rulenode.no-message-type-matching tb.rulenode.create-new-message-type
{{$chip.name}}
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-filter-function' | translate }}
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-switch-function' | translate }}
"},function(e,t){e.exports='
{{ keyText }} {{ valText }}  
{{keyRequiredText}}
{{valRequiredText}}
{{ \'tb.key-val.remove-entry\' | translate }} close
{{ \'tb.key-val.add-entry\' | translate }} add {{ \'action.add\' | translate }}
'},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
relation.relation-filters
"},function(e,t){e.exports='
{{ source.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-transformer-function' | translate }}
"},function(e,t){e.exports="
tb.rulenode.from-template-required
tb.rulenode.from-template-hint
tb.rulenode.to-template-required
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.subject-template-required
tb.rulenode.subject-template-hint
tb.rulenode.body-template-required
tb.rulenode.body-template-hint
"},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(6),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(7),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(8),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue,a.configuration.hasOwnProperty("relationTypes")||(a.configuration.relationTypes=[])},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(9),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(10),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(11),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.originator=null,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue,a.configuration.originatorId&&a.configuration.originatorType?a.originator={id:a.configuration.originatorId,entityType:a.configuration.originatorType}:a.originator=null,a.$watch("originator",function(e,t){angular.equals(e,t)||(a.originator?(s.$viewValue.originatorId=a.originator.id,s.$viewValue.originatorType=a.originator.entityType):(s.$viewValue.originatorId=null,s.$viewValue.originatorType=null))},!0)},a.testScript=function(e){var n=angular.copy(a.configuration.jsScript);i.testNodeScript(e,n,"generate",t.instant("tb.rulenode.generator")+"","Generate",["prevMsg","prevMetadata","prevMsgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(1);var r=n(12),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(13),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(74),r=i(a),o=n(52),l=i(o),s=n(57),d=i(s),u=n(54),c=i(u),m=n(53),g=i(m),p=n(61),f=i(p),b=n(68),v=i(b),y=n(69),h=i(y),q=n(67),x=i(q),$=n(60),k=i($),T=n(72),C=i(T),w=n(73),M=i(w),N=n(66),S=i(N),_=n(62),E=i(_),P=n(71),F=i(P),A=n(64),V=i(A),I=n(63),j=i(I),O=n(51),D=i(O),R=n(75),K=i(R),L=n(56),U=i(L),z=n(55),B=i(z),H=n(70),G=i(H),Y=n(58),Q=i(Y),J=n(65),W=i(J);t.default=angular.module("thingsboard.ruleChain.config.action",[]).directive("tbActionNodeTimeseriesConfig",r.default).directive("tbActionNodeAttributesConfig",l.default).directive("tbActionNodeGeneratorConfig",d.default).directive("tbActionNodeCreateAlarmConfig",c.default).directive("tbActionNodeClearAlarmConfig",g.default).directive("tbActionNodeLogConfig",f.default).directive("tbActionNodeRpcReplyConfig",v.default).directive("tbActionNodeRpcRequestConfig",h.default).directive("tbActionNodeRestApiCallConfig",x.default).directive("tbActionNodeKafkaConfig",k.default).directive("tbActionNodeSnsConfig",C.default).directive("tbActionNodeSqsConfig",M.default).directive("tbActionNodeRabbitMqConfig",S.default).directive("tbActionNodeMqttConfig",E.default).directive("tbActionNodeSendEmailConfig",F.default).directive("tbActionNodeMsgDelayConfig",V.default).directive("tbActionNodeMsgCountConfig",j.default).directive("tbActionNodeAssignToCustomerConfig",D.default).directive("tbActionNodeUnAssignToCustomerConfig",K.default).directive("tbActionNodeDeleteRelationConfig",U.default).directive("tbActionNodeCreateRelationConfig",B.default).directive("tbActionNodeCustomTableConfig",G.default).directive("tbActionNodeGpsGeofencingConfig",Q.default).directive("tbActionNodePubSubConfig",W.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.ackValues=["all","-1","0","1"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(14),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"string",t.instant("tb.rulenode.to-string")+"","ToString",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(15),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$mdExpansionPanel=t,i.ruleNodeTypes=n,i.credentialsTypeChanged=function(){var e=i.configuration.credentials.type;i.configuration.credentials={},i.configuration.credentials.type=e,i.updateValidity()},i.certFileAdded=function(e,t){var n=new FileReader;n.onload=function(n){i.$apply(function(){if(n.target.result){l.$setDirty();var a=n.target.result;a&&a.length>0&&("caCert"==t&&(i.configuration.credentials.caCertFileName=e.name,i.configuration.credentials.caCert=a),"privateKey"==t&&(i.configuration.credentials.privateKeyFileName=e.name,i.configuration.credentials.privateKey=a),"Cert"==t&&(i.configuration.credentials.certFileName=e.name,i.configuration.credentials.cert=a)),i.updateValidity()}})},n.readAsText(e.file)},i.clearCertFile=function(e){l.$setDirty(),"caCert"==e&&(i.configuration.credentials.caCertFileName=null,i.configuration.credentials.caCert=null),"privateKey"==e&&(i.configuration.credentials.privateKeyFileName=null,i.configuration.credentials.privateKey=null),"Cert"==e&&(i.configuration.credentials.certFileName=null,i.configuration.credentials.cert=null),i.updateValidity()},i.updateValidity=function(){var e=!0,t=i.configuration.credentials;t.type==n.mqttCredentialTypes["cert.PEM"].value&&(t.caCert&&t.cert&&t.privateKey||(e=!1)),l.$setValidity("Certs",e)},i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:i}}a.$inject=["$compile","$mdExpansionPanel","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(2);var r=n(16),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(17),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(18),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.serviceAccountFileAdded=function(e){var t=new FileReader;t.onload=function(t){n.$apply(function(){if(t.target.result){r.$setDirty();var i=t.target.result;i&&i.length>0&&(n.configuration.serviceAccountKeyFileName=e.name,n.configuration.serviceAccountKey=i),n.updateValidity()}})},t.readAsText(e.file)},n.clearServiceAccountFile=function(){r.$setDirty(),n.configuration.serviceAccountKeyFileName=null,n.configuration.serviceAccountKey=null,n.updateValidity()},n.updateValidity=function(){var e=!0,t=n.configuration;t.serviceAccountKeyFileName&&t.serviceAccountKey||(e=!1),r.$setValidity("SAKey",e)},n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(19),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(20),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(21),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(22),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(23),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue; -},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(24),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.smtpProtocols=["smtp","smtps"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(25),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(26),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(27),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(28),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(29),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(30),o=i(r)},function(e,t){"use strict";function n(e){var t=function(t,n,i,a){n.html("
"),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}n.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(31),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(32),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),n.entityDetailsList=[];for(var s in t.entityDetails){var d=s;n.entityDetailsList.push(d)}r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(33),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s);var d=186;i.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,d],i.ruleNodeTypes=n,i.aggPeriodTimeUnits={},i.aggPeriodTimeUnits.MINUTES=n.timeUnit.MINUTES,i.aggPeriodTimeUnits.HOURS=n.timeUnit.HOURS,i.aggPeriodTimeUnits.DAYS=n.timeUnit.DAYS,i.aggPeriodTimeUnits.MILLISECONDS=n.timeUnit.MILLISECONDS,i.aggPeriodTimeUnits.SECONDS=n.timeUnit.SECONDS,i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{},link:i}}a.$inject=["$compile","$mdConstant","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(34),o=i(r);n(3)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(83),r=i(a),o=n(84),l=i(o),s=n(79),d=i(s),u=n(85),c=i(u),m=n(78),g=i(m),p=n(86),f=i(p),b=n(81),v=i(b),y=n(80),h=i(y);t.default=angular.module("thingsboard.ruleChain.config.enrichment",[]).directive("tbEnrichmentNodeOriginatorAttributesConfig",r.default).directive("tbEnrichmentNodeOriginatorFieldsConfig",l.default).directive("tbEnrichmentNodeDeviceAttributesConfig",d.default).directive("tbEnrichmentNodeRelatedAttributesConfig",c.default).directive("tbEnrichmentNodeCustomerAttributesConfig",g.default).directive("tbEnrichmentNodeTenantAttributesConfig",f.default).directive("tbEnrichmentNodeGetTelemetryFromDatabase",v.default).directive("tbEnrichmentNodeEntityDetailsConfig",h.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(35),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(36),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(37),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(38),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(39),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(40),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(41),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(93),r=i(a),o=n(91),l=i(o),s=n(94),d=i(s),u=n(88),c=i(u),m=n(92),g=i(m),p=n(87),f=i(p),b=n(89),v=i(b);t.default=angular.module("thingsboard.ruleChain.config.filter",[]).directive("tbFilterNodeScriptConfig",r.default).directive("tbFilterNodeMessageTypeConfig",l.default).directive("tbFilterNodeSwitchConfig",d.default).directive("tbFilterNodeCheckRelationConfig",c.default).directive("tbFilterNodeOriginatorTypeConfig",g.default).directive("tbFilterNodeCheckMessageConfig",f.default).directive("tbFilterNodeGpsGeofencingConfig",v.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){function s(){if(l.$viewValue){for(var e=[],t=0;t-1&&t.kvList.splice(e,1)}function l(){t.kvList||(t.kvList=[]),t.kvList.push({key:"",value:""})}function s(){var e={};t.kvList.forEach(function(t){t.key&&(e[t.key]=t.value)}),a.$setViewValue(e),d()}function d(){var e=!0;t.required&&!t.kvList.length&&(e=!1),a.$setValidity("kvMap",e)}var u=o.default;n.html(u),t.ngModelCtrl=a,t.removeKeyVal=r,t.addKeyVal=l,t.kvList=[],t.$watch("query",function(e,n){angular.equals(e,n)||a.$setViewValue(t.query)}),a.$render=function(){if(a.$viewValue){var e=a.$viewValue;t.kvList.length=0;for(var n in e)t.kvList.push({key:n,value:e[n]})}t.$watch("kvList",function(e,t){angular.equals(e,t)||s()},!0),d()},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",disabled:"=ngDisabled",requiredText:"=",keyText:"=",keyRequiredText:"=",valText:"=",valRequiredText:"="},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(46),o=i(r);n(5)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(47),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(48),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(97),r=i(a),o=n(99),l=i(o),s=n(100),d=i(s);t.default=angular.module("thingsboard.ruleChain.config.transform",[]).directive("tbTransformationNodeChangeOriginatorConfig",r.default).directive("tbTransformationNodeScriptConfig",l.default).directive("tbTransformationNodeToEmailConfig",d.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"update",t.instant("tb.rulenode.transformer")+"","Transform",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(49),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(50),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(104),r=i(a),o=n(90),l=i(o),s=n(82),d=i(s),u=n(98),c=i(u),m=n(59),g=i(m),p=n(77),f=i(p),b=n(96),v=i(b),y=n(76),h=i(y),q=n(95),x=i(q),$=n(103),k=i($);t.default=angular.module("thingsboard.ruleChain.config",[r.default,l.default,d.default,c.default,g.default]).directive("tbNodeEmptyConfig",f.default).directive("tbRelationsQueryConfig",v.default).directive("tbDeviceRelationsQueryConfig",h.default).directive("tbKvMapConfig",x.default).config(k.default).name},function(e,t){"use strict";function n(e){var t={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-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","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-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","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.","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","latest-timeseries":"Latest timeseries","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-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","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 metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","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",propagate:"Propagate",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","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","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","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",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","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata","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","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","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","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","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 ${metaKeyName} in name/value fields to substitute variables from metadata","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","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","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"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 metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","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","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","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","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-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-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".',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}};e.translations("en_US",t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){(0,o.default)(e)}a.$inject=["$translateProvider"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(102),o=i(r)},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=angular.module("thingsboard.ruleChain.config.types",[]).constant("ruleNodeTypes",{originatorSource:{CUSTOMER:{name:"tb.rulenode.originator-customer",value:"CUSTOMER"},TENANT:{name:"tb.rulenode.originator-tenant",value:"TENANT"},RELATED:{name:"tb.rulenode.originator-related",value:"RELATED"},ALARM_ORIGINATOR:{name:"tb.rulenode.originator-alarm-originator",value:"ALARM_ORIGINATOR"}},fetchModeType:["FIRST","LAST","ALL"],samplingOrder:["ASC","DESC"],httpRequestType:["GET","POST","PUT","DELETE"],entityDetails:{TITLE:{name:"tb.rulenode.entity-details-title",value:"TITLE"},COUNTRY:{name:"tb.rulenode.entity-details-country",value:"COUNTRY"},STATE:{name:"tb.rulenode.entity-details-state",value:"STATE"},ZIP:{name:"tb.rulenode.entity-details-zip",value:"ZIP"},ADDRESS:{name:"tb.rulenode.entity-details-address",value:"ADDRESS"},ADDRESS2:{name:"tb.rulenode.entity-details-address2",value:"ADDRESS2"},PHONE:{name:"tb.rulenode.entity-details-phone",value:"PHONE"},EMAIL:{name:"tb.rulenode.entity-details-email",value:"EMAIL"},ADDITIONAL_INFO:{name:"tb.rulenode.entity-details-additional_info",value:"ADDITIONAL_INFO"}},sqsQueueType:{STANDARD:{name:"tb.rulenode.sqs-queue-standard",value:"STANDARD"},FIFO:{name:"tb.rulenode.sqs-queue-fifo",value:"FIFO"}},perimeterType:{CIRCLE:{name:"tb.rulenode.perimeter-circle",value:"CIRCLE"},POLYGON:{name:"tb.rulenode.perimeter-polygon",value:"POLYGON"}},timeUnit:{MILLISECONDS:{value:"MILLISECONDS",name:"tb.rulenode.time-unit-milliseconds"},SECONDS:{value:"SECONDS",name:"tb.rulenode.time-unit-seconds"},MINUTES:{value:"MINUTES",name:"tb.rulenode.time-unit-minutes"},HOURS:{value:"HOURS",name:"tb.rulenode.time-unit-hours"},DAYS:{value:"DAYS",name:"tb.rulenode.time-unit-days"}},rangeUnit:{METER:{value:"METER",name:"tb.rulenode.range-unit-meter"},KILOMETER:{value:"KILOMETER",name:"tb.rulenode.range-unit-kilometer"},FOOT:{value:"FOOT",name:"tb.rulenode.range-unit-foot"},MILE:{value:"MILE",name:"tb.rulenode.range-unit-mile"},NAUTICAL_MILE:{value:"NAUTICAL_MILE",name:"tb.rulenode.range-unit-nautical-mile"}},mqttCredentialTypes:{anonymous:{value:"anonymous",name:"tb.rulenode.credentials-anonymous"},basic:{value:"basic",name:"tb.rulenode.credentials-basic"},"cert.PEM":{value:"cert.PEM",name:"tb.rulenode.credentials-pem"}}}).name}])); +},function(e,t){e.exports="
tb.rulenode.interval-seconds-required
tb.rulenode.min-interval-seconds-message
tb.rulenode.output-timeseries-key-prefix-required
"},function(e,t){e.exports='
{{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
tb.rulenode.period-seconds-required
tb.rulenode.min-period-0-seconds-message
tb.rulenode.period-in-seconds-pattern-required
tb.rulenode.period-in-seconds-pattern-hint
tb.rulenode.max-pending-messages-required
tb.rulenode.max-pending-messages-range
tb.rulenode.max-pending-messages-range
'},function(e,t){e.exports="
tb.rulenode.gcp-project-id-required
tb.rulenode.pubsub-topic-name-required
{{ 'action.remove' | translate }} close
tb.rulenode.message-attributes-hint
"},function(e,t){e.exports='
{{ property }}
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
{{ \'tb.rulenode.automatic-recovery\' | translate }}
tb.rulenode.min-connection-timeout-ms-message
tb.rulenode.min-handshake-timeout-ms-message
'},function(e,t){e.exports='
tb.rulenode.endpoint-url-pattern-required
tb.rulenode.endpoint-url-pattern-hint
{{ type }} {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}
tb.rulenode.read-timeout-hint
tb.rulenode.max-parallel-requests-count-hint
tb.rulenode.headers-hint
{{ \'tb.rulenode.use-redis-queue\' | translate }}
{{ \'tb.rulenode.trim-redis-queue\' | translate }}
'},function(e,t){e.exports="
"},function(e,t){e.exports="
tb.rulenode.timeout-required
tb.rulenode.min-timeout-message
"},function(e,t){e.exports='
tb.rulenode.custom-table-name-required
tb.rulenode.custom-table-hint
'},function(e,t){e.exports='
{{ \'tb.rulenode.use-system-smtp-settings\' | translate }}
{{smtpProtocol.toUpperCase()}}
tb.rulenode.smtp-host-required
tb.rulenode.smtp-port-required
tb.rulenode.smtp-port-range
tb.rulenode.smtp-port-range
tb.rulenode.timeout-required
tb.rulenode.min-timeout-msec-message
{{ \'tb.rulenode.enable-tls\' | translate }}
'},function(e,t){e.exports="
tb.rulenode.topic-arn-pattern-required
tb.rulenode.topic-arn-pattern-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
"},function(e,t){e.exports='
{{ type.name | translate }}
tb.rulenode.queue-url-pattern-required
tb.rulenode.queue-url-pattern-hint
tb.rulenode.min-delay-seconds-message
tb.rulenode.max-delay-seconds-message
tb.rulenode.message-attributes-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
'},function(e,t){e.exports="
tb.rulenode.default-ttl-required
tb.rulenode.min-default-ttl-message
"},function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{ (\'relation.search-direction.\' + direction) | translate}}
relation.relation-type
device.device-types
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
{{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}
tb.rulenode.get-latest-value-with-ts-hint
'},function(e,t){e.exports='
{{\'tb.rulenode.entity-details-\'+item.toLowerCase() | translate}} tb.rulenode.no-entity-details-matching {{\'tb.rulenode.entity-details-\'+$chip.toLowerCase() | translate}} {{ \'tb.rulenode.add-to-metadata\' | translate }}
tb.rulenode.add-to-metadata-hint
'},function(e,t){e.exports='
{{ type }}
tb.rulenode.fetch-mode-hint
{{ type }}
tb.rulenode.order-by-hint
tb.rulenode.limit-hint
{{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}
tb.rulenode.use-metadata-interval-patterns-hint
tb.rulenode.start-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.end-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.start-interval-pattern-required
tb.rulenode.start-interval-pattern-hint
tb.rulenode.end-interval-pattern-required
tb.rulenode.end-interval-pattern-hint
'; +},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
{{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}
tb.rulenode.get-latest-value-with-ts-hint
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},31,function(e,t){e.exports='
tb.rulenode.separator-hint
tb.rulenode.separator-hint
{{ \'tb.rulenode.check-all-keys\' | translate }}
tb.rulenode.check-all-keys-hint
'},function(e,t){e.exports="
{{ 'tb.rulenode.check-relation-to-specific-entity' | translate }}
tb.rulenode.check-relation-hint
{{ ('relation.search-direction.' + direction) | translate}}
"},function(e,t){e.exports='
tb.rulenode.latitude-key-name-required
tb.rulenode.longitude-key-name-required
{{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}
{{ type.name | translate}}
tb.rulenode.circle-center-latitude-required
tb.rulenode.circle-center-longitude-required
tb.rulenode.range-required
{{ type.name | translate}}
tb.rulenode.polygon-definition-required
tb.rulenode.polygon-definition-hint
'},function(e,t){e.exports='
{{item}}
tb.rulenode.no-message-types-found
tb.rulenode.no-message-type-matching tb.rulenode.create-new-message-type
{{$chip.name}}
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-filter-function' | translate }}
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-switch-function' | translate }}
"},function(e,t){e.exports='
{{ keyText }} {{ valText }}  
{{keyRequiredText}}
{{valRequiredText}}
{{ \'tb.key-val.remove-entry\' | translate }} close
{{ \'tb.key-val.add-entry\' | translate }} add {{ \'action.add\' | translate }}
'},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
relation.relation-filters
"},function(e,t){e.exports='
{{ source.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-transformer-function' | translate }}
"},function(e,t){e.exports="
tb.rulenode.from-template-required
tb.rulenode.from-template-hint
tb.rulenode.to-template-required
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.subject-template-required
tb.rulenode.subject-template-hint
tb.rulenode.body-template-required
tb.rulenode.body-template-hint
"},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(6),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(7),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(8),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue,a.configuration.hasOwnProperty("relationTypes")||(a.configuration.relationTypes=[])},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(9),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(10),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(11),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.originator=null,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue,a.configuration.originatorId&&a.configuration.originatorType?a.originator={id:a.configuration.originatorId,entityType:a.configuration.originatorType}:a.originator=null,a.$watch("originator",function(e,t){angular.equals(e,t)||(a.originator?(s.$viewValue.originatorId=a.originator.id,s.$viewValue.originatorType=a.originator.entityType):(s.$viewValue.originatorId=null,s.$viewValue.originatorType=null))},!0)},a.testScript=function(e){var n=angular.copy(a.configuration.jsScript);i.testNodeScript(e,n,"generate",t.instant("tb.rulenode.generator")+"","Generate",["prevMsg","prevMetadata","prevMsgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(1);var r=n(12),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(13),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(74),r=i(a),o=n(52),l=i(o),s=n(57),d=i(s),u=n(54),c=i(u),m=n(53),g=i(m),p=n(61),f=i(p),b=n(68),v=i(b),y=n(69),h=i(y),q=n(67),x=i(q),k=n(60),$=i(k),T=n(72),C=i(T),w=n(73),M=i(w),N=n(66),S=i(N),_=n(62),E=i(_),F=n(71),P=i(F),A=n(64),V=i(A),I=n(63),j=i(I),O=n(51),D=i(O),R=n(75),K=i(R),L=n(56),U=i(L),z=n(55),H=i(z),B=n(70),G=i(B),Y=n(58),Q=i(Y),W=n(65),J=i(W);t.default=angular.module("thingsboard.ruleChain.config.action",[]).directive("tbActionNodeTimeseriesConfig",r.default).directive("tbActionNodeAttributesConfig",l.default).directive("tbActionNodeGeneratorConfig",d.default).directive("tbActionNodeCreateAlarmConfig",c.default).directive("tbActionNodeClearAlarmConfig",g.default).directive("tbActionNodeLogConfig",f.default).directive("tbActionNodeRpcReplyConfig",v.default).directive("tbActionNodeRpcRequestConfig",h.default).directive("tbActionNodeRestApiCallConfig",x.default).directive("tbActionNodeKafkaConfig",$.default).directive("tbActionNodeSnsConfig",C.default).directive("tbActionNodeSqsConfig",M.default).directive("tbActionNodeRabbitMqConfig",S.default).directive("tbActionNodeMqttConfig",E.default).directive("tbActionNodeSendEmailConfig",P.default).directive("tbActionNodeMsgDelayConfig",V.default).directive("tbActionNodeMsgCountConfig",j.default).directive("tbActionNodeAssignToCustomerConfig",D.default).directive("tbActionNodeUnAssignToCustomerConfig",K.default).directive("tbActionNodeDeleteRelationConfig",U.default).directive("tbActionNodeCreateRelationConfig",H.default).directive("tbActionNodeCustomTableConfig",G.default).directive("tbActionNodeGpsGeofencingConfig",Q.default).directive("tbActionNodePubSubConfig",J.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.ackValues=["all","-1","0","1"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(14),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"string",t.instant("tb.rulenode.to-string")+"","ToString",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(15),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$mdExpansionPanel=t,i.ruleNodeTypes=n,i.credentialsTypeChanged=function(){var e=i.configuration.credentials.type;i.configuration.credentials={},i.configuration.credentials.type=e,i.updateValidity()},i.certFileAdded=function(e,t){var n=new FileReader;n.onload=function(n){i.$apply(function(){if(n.target.result){l.$setDirty();var a=n.target.result;a&&a.length>0&&("caCert"==t&&(i.configuration.credentials.caCertFileName=e.name,i.configuration.credentials.caCert=a),"privateKey"==t&&(i.configuration.credentials.privateKeyFileName=e.name,i.configuration.credentials.privateKey=a),"Cert"==t&&(i.configuration.credentials.certFileName=e.name,i.configuration.credentials.cert=a)),i.updateValidity()}})},n.readAsText(e.file)},i.clearCertFile=function(e){l.$setDirty(),"caCert"==e&&(i.configuration.credentials.caCertFileName=null,i.configuration.credentials.caCert=null),"privateKey"==e&&(i.configuration.credentials.privateKeyFileName=null,i.configuration.credentials.privateKey=null),"Cert"==e&&(i.configuration.credentials.certFileName=null,i.configuration.credentials.cert=null),i.updateValidity()},i.updateValidity=function(){var e=!0,t=i.configuration.credentials;t.type==n.mqttCredentialTypes["cert.PEM"].value&&(t.caCert&&t.cert&&t.privateKey||(e=!1)),l.$setValidity("Certs",e)},i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:i}}a.$inject=["$compile","$mdExpansionPanel","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(2);var r=n(16),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(17),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(18),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.serviceAccountFileAdded=function(e){var t=new FileReader;t.onload=function(t){n.$apply(function(){if(t.target.result){r.$setDirty();var i=t.target.result;i&&i.length>0&&(n.configuration.serviceAccountKeyFileName=e.name,n.configuration.serviceAccountKey=i),n.updateValidity()}})},t.readAsText(e.file)},n.clearServiceAccountFile=function(){r.$setDirty(),n.configuration.serviceAccountKeyFileName=null,n.configuration.serviceAccountKey=null,n.updateValidity()},n.updateValidity=function(){var e=!0,t=n.configuration;t.serviceAccountKeyFileName&&t.serviceAccountKey||(e=!1),r.$setValidity("SAKey",e)},n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(19),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t); +};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(20),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(21),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(22),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(23),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(24),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.smtpProtocols=["smtp","smtps"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(25),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(26),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(27),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(28),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(29),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(30),o=i(r)},function(e,t){"use strict";function n(e){var t=function(t,n,i,a){n.html("
"),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}n.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(31),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(32),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),n.entityDetailsList=[];for(var s in t.entityDetails){var d=s;n.entityDetailsList.push(d)}r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(33),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s);var d=186;i.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,d],i.ruleNodeTypes=n,i.aggPeriodTimeUnits={},i.aggPeriodTimeUnits.MINUTES=n.timeUnit.MINUTES,i.aggPeriodTimeUnits.HOURS=n.timeUnit.HOURS,i.aggPeriodTimeUnits.DAYS=n.timeUnit.DAYS,i.aggPeriodTimeUnits.MILLISECONDS=n.timeUnit.MILLISECONDS,i.aggPeriodTimeUnits.SECONDS=n.timeUnit.SECONDS,i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{},link:i}}a.$inject=["$compile","$mdConstant","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(34),o=i(r);n(3)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(83),r=i(a),o=n(84),l=i(o),s=n(79),d=i(s),u=n(85),c=i(u),m=n(78),g=i(m),p=n(86),f=i(p),b=n(81),v=i(b),y=n(80),h=i(y);t.default=angular.module("thingsboard.ruleChain.config.enrichment",[]).directive("tbEnrichmentNodeOriginatorAttributesConfig",r.default).directive("tbEnrichmentNodeOriginatorFieldsConfig",l.default).directive("tbEnrichmentNodeDeviceAttributesConfig",d.default).directive("tbEnrichmentNodeRelatedAttributesConfig",c.default).directive("tbEnrichmentNodeCustomerAttributesConfig",g.default).directive("tbEnrichmentNodeTenantAttributesConfig",f.default).directive("tbEnrichmentNodeGetTelemetryFromDatabase",v.default).directive("tbEnrichmentNodeEntityDetailsConfig",h.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(35),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(36),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(37),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(38),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(39),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(40),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(41),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(93),r=i(a),o=n(91),l=i(o),s=n(94),d=i(s),u=n(88),c=i(u),m=n(92),g=i(m),p=n(87),f=i(p),b=n(89),v=i(b);t.default=angular.module("thingsboard.ruleChain.config.filter",[]).directive("tbFilterNodeScriptConfig",r.default).directive("tbFilterNodeMessageTypeConfig",l.default).directive("tbFilterNodeSwitchConfig",d.default).directive("tbFilterNodeCheckRelationConfig",c.default).directive("tbFilterNodeOriginatorTypeConfig",g.default).directive("tbFilterNodeCheckMessageConfig",f.default).directive("tbFilterNodeGpsGeofencingConfig",v.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){function s(){if(l.$viewValue){for(var e=[],t=0;t-1&&t.kvList.splice(e,1)}function l(){t.kvList||(t.kvList=[]),t.kvList.push({key:"",value:""})}function s(){var e={};t.kvList.forEach(function(t){t.key&&(e[t.key]=t.value)}),a.$setViewValue(e),d()}function d(){var e=!0;t.required&&!t.kvList.length&&(e=!1),a.$setValidity("kvMap",e)}var u=o.default;n.html(u),t.ngModelCtrl=a,t.removeKeyVal=r,t.addKeyVal=l,t.kvList=[],t.$watch("query",function(e,n){angular.equals(e,n)||a.$setViewValue(t.query)}),a.$render=function(){if(a.$viewValue){var e=a.$viewValue;t.kvList.length=0;for(var n in e)t.kvList.push({key:n,value:e[n]})}t.$watch("kvList",function(e,t){angular.equals(e,t)||s()},!0),d()},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",disabled:"=ngDisabled",requiredText:"=",keyText:"=",keyRequiredText:"=",valText:"=",valRequiredText:"="},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(46),o=i(r);n(5)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(47),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(48),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(97),r=i(a),o=n(99),l=i(o),s=n(100),d=i(s);t.default=angular.module("thingsboard.ruleChain.config.transform",[]).directive("tbTransformationNodeChangeOriginatorConfig",r.default).directive("tbTransformationNodeScriptConfig",l.default).directive("tbTransformationNodeToEmailConfig",d.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"update",t.instant("tb.rulenode.transformer")+"","Transform",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(49),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(50),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(104),r=i(a),o=n(90),l=i(o),s=n(82),d=i(s),u=n(98),c=i(u),m=n(59),g=i(m),p=n(77),f=i(p),b=n(96),v=i(b),y=n(76),h=i(y),q=n(95),x=i(q),k=n(103),$=i(k);t.default=angular.module("thingsboard.ruleChain.config",[r.default,l.default,d.default,c.default,g.default]).directive("tbNodeEmptyConfig",f.default).directive("tbRelationsQueryConfig",v.default).directive("tbDeviceRelationsQueryConfig",h.default).directive("tbKvMapConfig",x.default).config($.default).name},function(e,t){"use strict";function n(e){var t={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-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","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-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","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","latest-timeseries":"Latest timeseries","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-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","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 metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","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",propagate:"Propagate",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","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","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","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","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 ${metaKeyName} in header/value fields to substitute variables from metadata",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","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata","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","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","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","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","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 ${metaKeyName} in name/value fields to substitute variables from metadata","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","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","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"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 metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","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","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","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","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-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-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"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}};e.translations("en_US",t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){(0,o.default)(e)}a.$inject=["$translateProvider"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(102),o=i(r)},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=angular.module("thingsboard.ruleChain.config.types",[]).constant("ruleNodeTypes",{originatorSource:{CUSTOMER:{name:"tb.rulenode.originator-customer",value:"CUSTOMER"},TENANT:{name:"tb.rulenode.originator-tenant",value:"TENANT"},RELATED:{name:"tb.rulenode.originator-related",value:"RELATED"},ALARM_ORIGINATOR:{name:"tb.rulenode.originator-alarm-originator",value:"ALARM_ORIGINATOR"}},fetchModeType:["FIRST","LAST","ALL"],samplingOrder:["ASC","DESC"],httpRequestType:["GET","POST","PUT","DELETE"],entityDetails:{TITLE:{name:"tb.rulenode.entity-details-title",value:"TITLE"},COUNTRY:{name:"tb.rulenode.entity-details-country",value:"COUNTRY"},STATE:{name:"tb.rulenode.entity-details-state",value:"STATE"},ZIP:{name:"tb.rulenode.entity-details-zip",value:"ZIP"},ADDRESS:{name:"tb.rulenode.entity-details-address",value:"ADDRESS"},ADDRESS2:{name:"tb.rulenode.entity-details-address2",value:"ADDRESS2"},PHONE:{name:"tb.rulenode.entity-details-phone",value:"PHONE"},EMAIL:{name:"tb.rulenode.entity-details-email",value:"EMAIL"},ADDITIONAL_INFO:{name:"tb.rulenode.entity-details-additional_info",value:"ADDITIONAL_INFO"}},sqsQueueType:{STANDARD:{name:"tb.rulenode.sqs-queue-standard",value:"STANDARD"},FIFO:{name:"tb.rulenode.sqs-queue-fifo",value:"FIFO"}},perimeterType:{CIRCLE:{name:"tb.rulenode.perimeter-circle",value:"CIRCLE"},POLYGON:{name:"tb.rulenode.perimeter-polygon",value:"POLYGON"}},timeUnit:{MILLISECONDS:{value:"MILLISECONDS",name:"tb.rulenode.time-unit-milliseconds"},SECONDS:{value:"SECONDS",name:"tb.rulenode.time-unit-seconds"},MINUTES:{value:"MINUTES",name:"tb.rulenode.time-unit-minutes"},HOURS:{value:"HOURS",name:"tb.rulenode.time-unit-hours"},DAYS:{value:"DAYS",name:"tb.rulenode.time-unit-days"}},rangeUnit:{METER:{value:"METER",name:"tb.rulenode.range-unit-meter"},KILOMETER:{value:"KILOMETER",name:"tb.rulenode.range-unit-kilometer"},FOOT:{value:"FOOT",name:"tb.rulenode.range-unit-foot"},MILE:{value:"MILE",name:"tb.rulenode.range-unit-mile"},NAUTICAL_MILE:{value:"NAUTICAL_MILE",name:"tb.rulenode.range-unit-nautical-mile"}},mqttCredentialTypes:{anonymous:{value:"anonymous",name:"tb.rulenode.credentials-anonymous"},basic:{value:"basic",name:"tb.rulenode.credentials-basic"},"cert.PEM":{value:"cert.PEM",name:"tb.rulenode.credentials-pem"}}}).name}])); //# sourceMappingURL=rulenode-core-config.js.map \ No newline at end of file From 89dbad2cf70014dfe45fbb846418019bffbd8137 Mon Sep 17 00:00:00 2001 From: Michael Hamburger Date: Mon, 23 Dec 2019 14:06:29 +0100 Subject: [PATCH 21/46] added delete alarm to ui service (#2266) --- ui/src/app/api/alarm.service.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ui/src/app/api/alarm.service.js b/ui/src/app/api/alarm.service.js index f1b0513ec6..83848e2817 100644 --- a/ui/src/app/api/alarm.service.js +++ b/ui/src/app/api/alarm.service.js @@ -47,6 +47,7 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { saveAlarm: saveAlarm, ackAlarm: ackAlarm, clearAlarm: clearAlarm, + deleteAlarm: deleteAlarm, getAlarms: getAlarms, getHighestAlarmSeverity: getHighestAlarmSeverity, pollAlarms: pollAlarms, @@ -132,6 +133,21 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { return deferred.promise; } + function deleteAlarm(alarmId, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/alarm/' + alarmId; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.delete(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + function getAlarms(entityType, entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator, ascOrder, config) { var deferred = $q.defer(); var url = '/api/alarm/' + entityType + '/' + entityId + '?limit=' + pageLink.limit; From cea1381482bead3271998408cc1cb73506061e7b Mon Sep 17 00:00:00 2001 From: Michael Hamburger Date: Mon, 23 Dec 2019 14:07:12 +0100 Subject: [PATCH 22/46] add upgrade_dev_db.sh script, which allows to upgrade an already existing developer database (#2267) --- .../main/scripts/install/upgrade_dev_db.sh | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100755 application/src/main/scripts/install/upgrade_dev_db.sh diff --git a/application/src/main/scripts/install/upgrade_dev_db.sh b/application/src/main/scripts/install/upgrade_dev_db.sh new file mode 100755 index 0000000000..31c68ddf88 --- /dev/null +++ b/application/src/main/scripts/install/upgrade_dev_db.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# +# Copyright © 2016-2019 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. +# + +for i in "$@" +do +case $i in + --fromVersion=*) + FROM_VERSION="${i#*=}" + shift + ;; + *) + # unknown option + ;; +esac +done + +if [[ -z "${FROM_VERSION// }" ]]; then + echo "--fromVersion parameter is invalid or unspecified!" + echo "Usage: upgrade_dev_db.sh --fromVersion={VERSION}" + exit 1 +else + fromVersion="${FROM_VERSION// }" +fi + +BASE=${project.basedir}/target +CONF_FOLDER=${BASE}/conf +jarfile="${BASE}/thingsboard-${project.version}-boot.jar" +installDir=${BASE}/data +loadDemo=true + + +export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@" +export LOADER_PATH=${BASE}/conf,${BASE}/extensions +export SQL_DATA_FOLDER=${SQL_DATA_FOLDER:-/tmp} + + +run_user="$USER" + +sudo -u "$run_user" -s /bin/sh -c "java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \ + -Dinstall.data_dir=${installDir} \ + -Dinstall.load_demo=${loadDemo} \ + -Dspring.jpa.hibernate.ddl-auto=none \ + -Dinstall.upgrade=true \ + -Dinstall.upgrade.from_version=${fromVersion} \ + -Dlogging.config=logback.xml \ + org.springframework.boot.loader.PropertiesLauncher" + +if [ $? -ne 0 ]; then + echo "ThingsBoard DB installation failed!" +else + echo "ThingsBoard DB installed successfully!" +fi + +exit $? From 4f8616d0af932698a8adf44132387771a05deadf Mon Sep 17 00:00:00 2001 From: Mirco Pizzichini <52463156+mircopz@users.noreply.github.com> Date: Mon, 23 Dec 2019 14:08:00 +0100 Subject: [PATCH 23/46] Fix timewindow parameters when zooming flot widget chart (#2271) --- ui/src/app/api/time.service.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/src/app/api/time.service.js b/ui/src/app/api/time.service.js index 6b2e3f7687..56b7f0735b 100644 --- a/ui/src/app/api/time.service.js +++ b/ui/src/app/api/time.service.js @@ -281,6 +281,9 @@ function TimeService($translate, $http, $q, types) { var historyTimewindow = { + hideInterval: timewindow.hideInterval || false, + hideAggregation: timewindow.hideAggregation || false, + hideAggInterval: timewindow.hideAggInterval || false, history: { fixedTimewindow: { startTimeMs: startTimeMs, From 518e9ac9418c420ac951a41c0bd3387aa0ed2cf0 Mon Sep 17 00:00:00 2001 From: Oleg Kolesnik <31017535+jktu2870@users.noreply.github.com> Date: Mon, 23 Dec 2019 15:31:47 +0200 Subject: [PATCH 24/46] Control widgets background color (#2286) * UI:fix. Dashboard (widgets order mobile view) * UI:fix. Control widgets (background-color setting doesn't work for some of them) --- .../data/json/system/widget_bundles/control_widgets.json | 8 ++++---- ui/src/app/widget/lib/rpc/knob.scss | 3 --- ui/src/app/widget/lib/rpc/led-indicator.scss | 3 --- ui/src/app/widget/lib/rpc/round-switch.scss | 3 --- ui/src/app/widget/lib/rpc/switch.scss | 3 --- 5 files changed, 4 insertions(+), 16 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/control_widgets.json b/application/src/main/data/json/system/widget_bundles/control_widgets.json index 44f7d52ebf..9f1b8cea10 100644 --- a/application/src/main/data/json/system/widget_bundles/control_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/control_widgets.json @@ -50,7 +50,7 @@ "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\",\n \"default\": 0\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\",\n \"default\": 100\n },\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"number\",\n \"default\": 50\n },\n \"title\": {\n \"title\": \"Knob title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"getValueMethod\": {\n \"title\": \"Get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"Set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"minValue\", \"maxValue\", \"getValueMethod\", \"setValueMethod\", \"requestTimeout\"]\n },\n \"form\": [\n \"minValue\",\n \"maxValue\",\n \"initialValue\",\n \"title\",\n \"getValueMethod\",\n \"setValueMethod\",\n \"requestTimeout\"\n ]\n}", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"maxValue\":100,\"initialValue\":50,\"minValue\":0,\"title\":\"Knob control\",\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\"},\"title\":\"Knob Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"maxValue\":100,\"initialValue\":50,\"minValue\":0,\"title\":\"Knob control\",\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\"},\"title\":\"Knob Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" } }, { @@ -66,7 +66,7 @@ "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showOnOffLabels\": {\n \"title\": \"Show on/off labels\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n \"showOnOffLabels\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" } }, { @@ -82,7 +82,7 @@ "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"title\":\"Round switch\",\"retrieveValueMethod\":\"rpc\",\"valueKey\":\"value\",\"parseValueFunction\":\"return data ? true : false;\",\"convertValueFunction\":\"return value;\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"title\":\"Round switch\",\"retrieveValueMethod\":\"rpc\",\"valueKey\":\"value\",\"parseValueFunction\":\"return data ? true : false;\",\"convertValueFunction\":\"return value;\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" } }, { @@ -98,7 +98,7 @@ "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"performCheckStatus\": {\n \"title\": \"Perform RPC device status check\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"checkStatusMethod\": {\n \"title\": \"RPC check device status method\",\n \"type\": \"string\",\n \"default\": \"checkStatus\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve led status value using method\",\n \"type\": \"string\",\n \"default\": \"attribute\"\n },\n \"valueAttribute\": {\n \"title\": \"Device attribute/timeseries containing led status value\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse led status value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"valueAttribute\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"performCheckStatus\",\n \"checkStatusMethod\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueAttribute\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valueAttribute\":\"value\",\"retrieveValueMethod\":\"attribute\",\"parseValueFunction\":\"return data ? true : false;\",\"performCheckStatus\":true,\"checkStatusMethod\":\"checkStatus\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valueAttribute\":\"value\",\"retrieveValueMethod\":\"attribute\",\"parseValueFunction\":\"return data ? true : false;\",\"performCheckStatus\":true,\"checkStatusMethod\":\"checkStatus\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" } }, { diff --git a/ui/src/app/widget/lib/rpc/knob.scss b/ui/src/app/widget/lib/rpc/knob.scss index 568994d391..19009d9227 100644 --- a/ui/src/app/widget/lib/rpc/knob.scss +++ b/ui/src/app/widget/lib/rpc/knob.scss @@ -26,12 +26,9 @@ $minmax-height: percentage(.04) !default; $minmax-container-margin-pct: percentage(.18) !default; $minmax-container-margin-bottom-pct: percentage(.12) !default; -$background-color: #e6e7e8 !default; - .tb-knob { width: 100%; height: 100%; - background: $background-color; .knob { position: relative; diff --git a/ui/src/app/widget/lib/rpc/led-indicator.scss b/ui/src/app/widget/lib/rpc/led-indicator.scss index 7fe825dab7..4d058cffb9 100644 --- a/ui/src/app/widget/lib/rpc/led-indicator.scss +++ b/ui/src/app/widget/lib/rpc/led-indicator.scss @@ -17,12 +17,9 @@ $error-height: 14px !default; -$background-color: #e6e7e8 !default; - .tb-led-indicator { width: 100%; height: 100%; - background: $background-color; .title-container { .led-title { diff --git a/ui/src/app/widget/lib/rpc/round-switch.scss b/ui/src/app/widget/lib/rpc/round-switch.scss index bc2cc4a929..50eaa6db75 100644 --- a/ui/src/app/widget/lib/rpc/round-switch.scss +++ b/ui/src/app/widget/lib/rpc/round-switch.scss @@ -17,12 +17,9 @@ $error-height: 14px !default; -$background-color: #e6e7e8 !default; - .tb-round-switch { width: 100%; height: 100%; - background: $background-color; .title-container { .switch-title { diff --git a/ui/src/app/widget/lib/rpc/switch.scss b/ui/src/app/widget/lib/rpc/switch.scss index 72500ff03e..7045a4bf05 100644 --- a/ui/src/app/widget/lib/rpc/switch.scss +++ b/ui/src/app/widget/lib/rpc/switch.scss @@ -18,14 +18,11 @@ $thumb-checked-img: url("./svg/thumb-checked.svg") !default; $thumb-bar-img: url("./svg/thumb-bar.svg") !default; $thumb-bar-checked-img: url("./svg/thumb-bar-checked.svg") !default; -$background-color: #e6e7e8 !default; - $error-height: 14px !default; .tb-switch { width: 100%; height: 100%; - background: $background-color; .error-container { position: absolute; From 825406690c5d5896189ea3caf3e2abca65c94b40 Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Mon, 23 Dec 2019 15:45:27 +0200 Subject: [PATCH 25/46] Flot widget pull requests: resolve conflicts for #2053, #2061 (#2289) * Add some datakey settings to edit legend appearance for flot widget * Fix timestamp and index search in 'line' flot charts tooltip Co-authored-by: Mirco Pizzichini <52463156+mircopz@users.noreply.github.com> --- ui/src/app/api/subscription.js | 3 +- ui/src/app/components/legend.directive.js | 4 +- ui/src/app/components/legend.tpl.html | 25 ++++++++--- ui/src/app/widget/lib/flot-widget.js | 55 ++++++++++++++++++++--- 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js index 89f8aae309..4ad374bfe4 100644 --- a/ui/src/app/api/subscription.js +++ b/ui/src/app/api/subscription.js @@ -332,7 +332,8 @@ export default class Subscription { for (var a = 0; a < datasource.dataKeys.length; a++) { var dataKey = datasource.dataKeys[a]; - dataKey.hidden = false; + dataKey.hidden = dataKey.settings.hideDataByDefault ? true : false; + dataKey.inLegend = dataKey.settings.removeFromLegend ? false : true; dataKey.pattern = angular.copy(dataKey.label); if (this.comparisonEnabled && dataKey.settings.comparisonSettings && dataKey.settings.comparisonSettings.showValuesForComparison) { diff --git a/ui/src/app/components/legend.directive.js b/ui/src/app/components/legend.directive.js index 76ffdb4e78..bed10e3f52 100644 --- a/ui/src/app/components/legend.directive.js +++ b/ui/src/app/components/legend.directive.js @@ -46,7 +46,9 @@ function Legend($compile, $templateCache, types) { scope.isRowDirection = scope.legendConfig.direction === types.direction.row.value; scope.toggleHideData = function(index) { - scope.legendData.keys[index].dataKey.hidden = !scope.legendData.keys[index].dataKey.hidden; + if (!scope.legendData.keys[index].dataKey.settings.disableDataHiding) { + scope.legendData.keys[index].dataKey.hidden = !scope.legendData.keys[index].dataKey.hidden; + } } $compile(element.contents())(scope); diff --git a/ui/src/app/components/legend.tpl.html b/ui/src/app/components/legend.tpl.html index 157835729b..d77bb1193c 100644 --- a/ui/src/app/components/legend.tpl.html +++ b/ui/src/app/components/legend.tpl.html @@ -27,7 +27,8 @@ - + - + {{ 'legend.min' | translate }} - {{ legendData.data[legendKey.dataIndex].min }} + + {{ legendData.data[legendKey.dataIndex].min }} + {{ 'legend.max' | translate }} - {{ legendData.data[legendKey.dataIndex].max }} + + {{ legendData.data[legendKey.dataIndex].max }} + {{ 'legend.avg' | translate }} - {{ legendData.data[legendKey.dataIndex].avg }} + + {{ legendData.data[legendKey.dataIndex].avg }} + {{ 'legend.total' | translate }} - {{ legendData.data[legendKey.dataIndex].total }} + + {{ legendData.data[legendKey.dataIndex].total }} + diff --git a/ui/src/app/widget/lib/flot-widget.js b/ui/src/app/widget/lib/flot-widget.js index 08496d574b..063c68a4da 100644 --- a/ui/src/app/widget/lib/flot-widget.js +++ b/ui/src/app/widget/lib/flot-widget.js @@ -139,12 +139,7 @@ export default class TbFlot { return seriesHover.index === seriesIndex; }); if (found && found.length) { - let timestamp; - if (!angular.isNumber(hoverInfo[0].time) || (found[0].time < hoverInfo[0].time)) { - timestamp = parseInt(hoverInfo[1].time); - } else { - timestamp = parseInt(hoverInfo[0].time); - } + let timestamp = parseInt(found[0].time); let date = moment(timestamp).format('YYYY-MM-DD HH:mm:ss'); let dateDiv = $('
' + date + '
'); dateDiv.css({ @@ -1213,7 +1208,35 @@ export default class TbFlot { } static get pieDatakeySettingsSchema() { - return {} + return { + "schema": { + "type": "object", + "title": "DataKeySettings", + "properties": { + "hideDataByDefault": { + "title": "Data is hidden by default", + "type": "boolean", + "default": false + }, + "disableDataHiding": { + "title": "Disable data hiding", + "type": "boolean", + "default": false + }, + "removeFromLegend": { + "title": "Remove datakey from legend", + "type": "boolean", + "default": false + } + }, + "required": [] + }, + "form": [ + "hideDataByDefault", + "disableDataHiding", + "removeFromLegend" + ] + }; } static datakeySettingsSchema(defaultShowLines, chartType) { @@ -1228,6 +1251,21 @@ export default class TbFlot { "type": "boolean", "default": false }, + "hideDataByDefault": { + "title": "Data is hidden by default", + "type": "boolean", + "default": false + }, + "disableDataHiding": { + "title": "Disable data hiding", + "type": "boolean", + "default": false + }, + "removeFromLegend": { + "title": "Remove datakey from legend", + "type": "boolean", + "default": false + }, "showLines": { "title": "Show lines", "type": "boolean", @@ -1316,6 +1354,9 @@ export default class TbFlot { "required": ["showLines", "fillLines", "showPoints"] }, "form": [ + "hideDataByDefault", + "disableDataHiding", + "removeFromLegend", "excludeFromStacking", "showLines", "fillLines", From 6ba0b943e88118ee544988b7d8335f4b7aa46246 Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Mon, 23 Dec 2019 17:35:04 +0200 Subject: [PATCH 26/46] Create new dataKey type entityField (#2282) * Add support import label * Create new dataKey type entityField * Add translate to entityField --- ui/src/app/api/entity.service.js | 43 ++++++++++ ui/src/app/api/subscription.js | 15 +++- ui/src/app/app.config.js | 5 +- ui/src/app/common/types.constant.js | 81 ++++++++++++++++++- ui/src/app/components/datakey-config.tpl.html | 6 +- .../components/datasource-entity.directive.js | 16 ++-- .../app/components/datasource-entity.tpl.html | 12 +++ .../widget/widget-config.directive.js | 8 +- ui/src/app/locale/locale.constant-el_GR.json | 18 ++++- ui/src/app/locale/locale.constant-en_US.json | 17 ++++ ui/src/app/locale/locale.constant-es_ES.json | 16 ++++ ui/src/app/locale/locale.constant-fr_FR.json | 16 ++++ ui/src/app/locale/locale.constant-ru_RU.json | 17 ++++ ui/src/app/locale/locale.constant-uk_UA.json | 17 ++++ 14 files changed, 268 insertions(+), 19 deletions(-) diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index 5ce4fd7108..51336ee374 100644 --- a/ui/src/app/api/entity.service.js +++ b/ui/src/app/api/entity.service.js @@ -848,7 +848,50 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device return deferred.promise; } + function getEntityFieldKeys (entityType, searchText) { + let entityFieldKeys = []; + let query = searchText.toLowerCase(); + switch(entityType) { + case types.entityType.user: + entityFieldKeys.push(types.entityField.name.keyName); + entityFieldKeys.push(types.entityField.email.keyName); + entityFieldKeys.push(types.entityField.firstName.keyName); + entityFieldKeys.push(types.entityField.lastName.keyName); + break; + case types.entityType.tenant: + case types.entityType.customer: + entityFieldKeys.push(types.entityField.title.keyName); + entityFieldKeys.push(types.entityField.email.keyName); + entityFieldKeys.push(types.entityField.country.keyName); + entityFieldKeys.push(types.entityField.state.keyName); + entityFieldKeys.push(types.entityField.city.keyName); + entityFieldKeys.push(types.entityField.address.keyName); + entityFieldKeys.push(types.entityField.address2.keyName); + entityFieldKeys.push(types.entityField.zip.keyName); + entityFieldKeys.push(types.entityField.phone.keyName); + break; + case types.entityType.entityView: + entityFieldKeys.push(types.entityField.name.keyName); + entityFieldKeys.push(types.entityField.type.keyName); + break; + case types.entityType.device: + case types.entityType.asset: + entityFieldKeys.push(types.entityField.name.keyName); + entityFieldKeys.push(types.entityField.type.keyName); + entityFieldKeys.push(types.entityField.label.keyName); + break; + case types.entityType.dashboard: + entityFieldKeys.push(types.entityField.title.keyName); + break; + } + + return query ? entityFieldKeys.filter((entityField) => entityField.toLowerCase().indexOf(query) === 0) : entityFieldKeys; + } + function getEntityKeys(entityType, entityId, query, type, config) { + if (type === types.dataKeyType.entityField) { + return $q.when(getEntityFieldKeys(entityType, query)); + } var deferred = $q.defer(); var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; if (type === types.dataKeyType.timeseries) { diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js index 4ad374bfe4..86ab823294 100644 --- a/ui/src/app/api/subscription.js +++ b/ui/src/app/api/subscription.js @@ -350,6 +350,11 @@ export default class Subscription { dataKey: dataKey, data: [] }; + if (dataKey.type === this.ctx.types.dataKeyType.entityField) { + if(datasource.entity && datasource.entity[this.ctx.types.entityField[dataKey.name].value]){ + datasourceData.data.push([Date.now(), datasource.entity[this.ctx.types.entityField[dataKey.name].value]]); + } + } this.data.push(datasourceData); this.hiddenData.push({data: []}); if (this.displayLegend) { @@ -878,8 +883,14 @@ export default class Subscription { }; } + var entityFieldKey = false; + for (var a = 0; a < datasource.dataKeys.length; a++) { - this.data[index + a].data = []; + if (datasource.dataKeys[a].type !== this.ctx.types.dataKeyType.entityField) { + this.data[index + a].data = []; + } else { + entityFieldKey = true; + } } index += datasource.dataKeys.length; @@ -891,7 +902,7 @@ export default class Subscription { } var forceUpdate = false; - if (datasource.unresolvedStateEntity || + if (datasource.unresolvedStateEntity || entityFieldKey || !datasource.dataKeys.length || (datasource.type === this.ctx.types.datasourceType.entity && !datasource.entityId) ) { diff --git a/ui/src/app/app.config.js b/ui/src/app/app.config.js index c38deae93b..d441d87d8b 100644 --- a/ui/src/app/app.config.js +++ b/ui/src/app/app.config.js @@ -78,7 +78,8 @@ export default function AppConfig($provide, $mdIconProvider.iconSet('mdi', mdiIconSet); ngMdIconServiceProvider - .addShape('alpha-a-circle-outline', ''); + .addShape('alpha-a-circle-outline', '') + .addShape('alpha-e-circle-outline', ''); configureTheme(); @@ -170,4 +171,4 @@ export default function AppConfig($provide, return aliases; } -} \ No newline at end of file +} diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index e6e65bbecf..6b11af555f 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -322,7 +322,8 @@ export default angular.module('thingsboard.types', []) timeseries: "timeseries", attribute: "attribute", function: "function", - alarm: "alarm" + alarm: "alarm", + entityField: "entityField" }, contentType: { "JSON": { @@ -467,6 +468,84 @@ export default angular.module('thingsboard.types', []) list: 'entity.type-current-customer' } }, + entityField: { + createdTime: { + keyName: 'createdTime', + name: 'entity-field.created-time', + value: 'createdTime', + time: true + }, + name: { + keyName: 'name', + name: 'entity-field.name', + value: 'name' + }, + type: { + keyName: 'type', + name: 'entity-field.type', + value: 'type' + }, + firstName: { + keyName: 'firstName', + name: 'entity-field.first-name', + value: 'firstName' + }, + lastName: { + keyName: 'lastName', + name: 'entity-field.last-name', + value: 'lastName' + }, + email: { + keyName: 'email', + name: 'entity-field.email', + value: 'email' + }, + title: { + keyName: 'title', + name: 'entity-field.title', + value: 'title' + }, + country: { + keyName: 'country', + name: 'entity-field.country', + value: 'country' + }, + state: { + keyName: 'state', + name: 'entity-field.state', + value: 'state' + }, + city: { + keyName: 'city', + name: 'entity-field.city', + value: 'city' + }, + address: { + keyName: 'address', + name: 'entity-field.address', + value: 'address' + }, + address2: { + keyName: 'address2', + name: 'entity-field.address2', + value: 'address2' + }, + zip: { + keyName: 'zip', + name: 'entity-field.zip', + value: 'zip' + }, + phone: { + keyName: 'phone', + name: 'entity-field.phone', + value: 'phone' + }, + label: { + keyName: 'label', + name: 'entity-field.label', + value: 'label' + } + }, entitySearchDirection: { from: "FROM", to: "TO" diff --git a/ui/src/app/components/datakey-config.tpl.html b/ui/src/app/components/datakey-config.tpl.html index 0b5b11d690..f8da179141 100644 --- a/ui/src/app/components/datakey-config.tpl.html +++ b/ui/src/app/components/datakey-config.tpl.html @@ -16,9 +16,7 @@ --> - - \ No newline at end of file + diff --git a/ui/src/app/components/datasource-entity.directive.js b/ui/src/app/components/datasource-entity.directive.js index 9ed05b8812..844e60e97e 100644 --- a/ui/src/app/components/datasource-entity.directive.js +++ b/ui/src/app/components/datasource-entity.directive.js @@ -124,7 +124,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc var alarmDataKeys = []; for (var d in ngModelCtrl.$viewValue.dataKeys) { var dataKey = ngModelCtrl.$viewValue.dataKeys[d]; - if ((dataKey.type === types.dataKeyType.timeseries) || (dataKey.type === types.dataKeyType.attribute)) { + if ((dataKey.type === types.dataKeyType.timeseries) || (dataKey.type === types.dataKeyType.attribute) || (dataKey.type === types.dataKeyType.entityField)) { dataKeys.push(dataKey); } else if (dataKey.type === types.dataKeyType.alarm) { alarmDataKeys.push(dataKey); @@ -219,7 +219,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc w.triggerHandler('resize'); } }).then(function (newDataKey) { - if ((newDataKey.type === types.dataKeyType.timeseries) || (newDataKey.type === types.dataKeyType.attribute)) { + if ((newDataKey.type === types.dataKeyType.timeseries) || (newDataKey.type === types.dataKeyType.attribute) || (newDataKey.type === types.dataKeyType.entityField)) { let index = scope.dataKeys.indexOf(dataKey); scope.dataKeys[index] = newDataKey; } else if (newDataKey.type === types.dataKeyType.alarm) { @@ -246,10 +246,16 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc items.push({ name: dataKeys[i], type: types.dataKeyType.timeseries }); } if (scope.widgetType == types.widgetType.latest.value) { - scope.fetchEntityKeys({entityAliasId: scope.entityAlias.id, query: searchText, type: types.dataKeyType.attribute}) - .then(function (dataKeys) { + var keysType = [types.dataKeyType.attribute, types.dataKeyType.entityField]; + var promises = []; + keysType.forEach((type) => { + promises.push(scope.fetchEntityKeys({entityAliasId: scope.entityAlias.id, query: searchText, type: type})); + }); + $q.all(promises).then(function (dataKeys) { for (var i = 0; i < dataKeys.length; i++) { - items.push({ name: dataKeys[i], type: types.dataKeyType.attribute }); + for (var j = 0; j < dataKeys[i].length; j++) { + items.push({name: dataKeys[i][j], type: keysType[i]}); + } } deferred.resolve(items); }, function (e) { diff --git a/ui/src/app/components/datasource-entity.tpl.html b/ui/src/app/components/datasource-entity.tpl.html index fe0d23eef7..a167d313ee 100644 --- a/ui/src/app/components/datasource-entity.tpl.html +++ b/ui/src/app/components/datasource-entity.tpl.html @@ -43,6 +43,10 @@ {{'datakey.attributes' | translate }}
+ + {{'datakey.entityField' | translate }} + + {{'datakey.timeseries' | translate }} @@ -60,6 +64,10 @@ {{'datakey.attributes' | translate }} + + {{'datakey.entityField' | translate }} + + {{'datakey.timeseries' | translate }} @@ -81,6 +89,10 @@ {{'datakey.attributes' | translate }} + + + {{'datakey.entityField' | translate }} + {{'datakey.timeseries' | translate }} diff --git a/ui/src/app/components/widget/widget-config.directive.js b/ui/src/app/components/widget/widget-config.directive.js index 470726a835..2fe97ce6d6 100644 --- a/ui/src/app/components/widget/widget-config.directive.js +++ b/ui/src/app/components/widget/widget-config.directive.js @@ -423,10 +423,10 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout } var label = chip; - if (type === types.dataKeyType.alarm) { - var alarmField = types.alarmFields[chip]; - if (alarmField) { - label = $translate.instant(alarmField.name)+''; + if (type === types.dataKeyType.alarm || type === types.dataKeyType.entityField) { + var keyField = type === types.dataKeyType.alarm ? types.alarmFields[chip] : types.entityField[chip]; + if (keyField) { + label = $translate.instant(keyField.name)+''; } } label = scope.genNextLabel(label); diff --git a/ui/src/app/locale/locale.constant-el_GR.json b/ui/src/app/locale/locale.constant-el_GR.json index b590c70e47..f3051e98c1 100644 --- a/ui/src/app/locale/locale.constant-el_GR.json +++ b/ui/src/app/locale/locale.constant-el_GR.json @@ -1102,6 +1102,22 @@ "copyId": "Αντιγραφή ID ομάδας οντοτήτων", "idCopiedMessage": "Το ID της ομάδας οντοτήτων έχει αντιγραφεί στο πρόχειρο" }, + "entity-field": { + "created-time": "Δημιουργήθηκε", + "name": "Όνομα", + "type": "Τύπος", + "first-name": "Όνομα", + "last-name": "Επίθετο", + "email": "Email", + "title": "Τίτλος", + "country": "Χώρα", + "state": "Νομός", + "city": "Πόλη", + "address": "Διεύθυνση", + "address2": "Διεύθυνση 2", + "zip": "Τ.Κ.", + "phone": "Τηλέφωνο" + }, "entity-view": { "entity-view": "Όψη Οντότητας", "entity-view-required": "Απαιτείται προβολή οντότητας.", @@ -2603,4 +2619,4 @@ "el_GR": "Ελληνικά" } } -} \ No newline at end of file +} diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 67f3fb09de..6310438128 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -815,6 +815,23 @@ "no-data": "No data to display", "columns-to-display": "Columns to Display" }, + "entity-field": { + "created-time": "Created time", + "name": "Name", + "type": "Type", + "first-name": "First name", + "last-name": "Last name", + "email": "Email", + "title": "Title", + "country": "Country", + "state": "State", + "city": "City", + "address": "Address", + "address2": "Address 2", + "zip": "Zip", + "phone": "Phone", + "label": "Label" + }, "entity-view": { "entity-view": "Entity View", "entity-view-required": "Entity view is required.", diff --git a/ui/src/app/locale/locale.constant-es_ES.json b/ui/src/app/locale/locale.constant-es_ES.json index d3d1c4042f..5cebe22ef6 100644 --- a/ui/src/app/locale/locale.constant-es_ES.json +++ b/ui/src/app/locale/locale.constant-es_ES.json @@ -808,6 +808,22 @@ "no-data": "No hay datos para mostrar", "columns-to-display": "Columnas a mostrar" }, + "entity-field": { + "created-time": "Tiempo de creación", + "name": "Nombre", + "type": "Tipo", + "first-name": "Nombre", + "last-name": "Apellido", + "email": "Correo electrónico", + "title": "Título", + "country": "País", + "state": "Estado", + "city": "Ciudad", + "address": "Dirección", + "address2": "Dirección 2", + "zip": "Código postal", + "phone": "Teléfono" + }, "entity-view": { "entity-view": "Vista de entidad", "entity-view-required": "Vista de entidad es requerido.", diff --git a/ui/src/app/locale/locale.constant-fr_FR.json b/ui/src/app/locale/locale.constant-fr_FR.json index b25a532927..5c922bfd49 100644 --- a/ui/src/app/locale/locale.constant-fr_FR.json +++ b/ui/src/app/locale/locale.constant-fr_FR.json @@ -809,6 +809,22 @@ "use-entity-name-filter": "Utiliser un filtre", "user-name-starts-with": "Utilisateurs dont les noms commencent par '{{prefix}}'" }, + "entity-field": { + "address": "Adresse", + "address2": "Adresse 2", + "city": "Ville", + "country": "Pays", + "created-time": "Heure de création", + "email": "Email", + "first-name": "Prénom", + "last-name": "Nom de famille", + "name": "Nom", + "phone": "Téléphone", + "state": "Prov", + "title": "Titre", + "type": "Type", + "zip": "Code postal" + }, "entity-view": { "add": "Ajouter une vue d'entité", "add-alias": "Ajouter un alias de vue d'entité", diff --git a/ui/src/app/locale/locale.constant-ru_RU.json b/ui/src/app/locale/locale.constant-ru_RU.json index 3aaa3042c5..ca4570638a 100644 --- a/ui/src/app/locale/locale.constant-ru_RU.json +++ b/ui/src/app/locale/locale.constant-ru_RU.json @@ -814,6 +814,23 @@ "no-data": "Нет данных для отображения", "columns-to-display": "Отобразить следующие колонки" }, + "entity-field": { + "created-time": "Время создания", + "name": "Название", + "type": "Тип", + "first-name": "Имя", + "last-name": "Фамилия", + "email": "Электронная почта", + "title": "Название", + "country": "Страна", + "state": "Штат/Область", + "city": "Город", + "address": "Адрес", + "address2": "Адрес 2", + "zip": "Индекс", + "phone": "Телефон", + "label": "Метка" + }, "entity-view": { "entity-view": "Представление Объекта", "entity-view-required": "Представление объекта обязательно.", diff --git a/ui/src/app/locale/locale.constant-uk_UA.json b/ui/src/app/locale/locale.constant-uk_UA.json index cbbaabd666..49fd45a409 100644 --- a/ui/src/app/locale/locale.constant-uk_UA.json +++ b/ui/src/app/locale/locale.constant-uk_UA.json @@ -956,6 +956,23 @@ "list-of-integrations": "{ count, plural, 1 {Одна інтеграція} other {Список # інтеграцій} }", "integration-name-starts-with": "Інтеграції, імена яких починаються з '{{prefix}}'" }, + "entity-field": { + "created-time": "Час створення", + "name": "Ім'я", + "type": "Тип", + "first-name": "Ім'я", + "last-name": "Прізвище", + "email": "Електронна пошта", + "title": "Назва", + "country": "Країна", + "state": "Штат", + "city": "Місто", + "address": "Адреса", + "address2": "Адреса 2", + "zip": "Zip", + "phone": "Телефон", + "label": "Мітка" + }, "entity-group": { "entity-group": "Група сутності", "details": "Деталі", From a93c8e25bac71379dd345547a48daf8ec99a4dee Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Mon, 23 Dec 2019 17:35:49 +0200 Subject: [PATCH 27/46] Hide timewindow when all options are hidden (#2287) * Hide timewindow when all options are hidden * Disable timewindow button when all options hidden --- ui/src/app/components/timewindow-button.tpl.html | 2 +- ui/src/app/components/timewindow.directive.js | 7 ++++++- ui/src/app/components/timewindow.tpl.html | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ui/src/app/components/timewindow-button.tpl.html b/ui/src/app/components/timewindow-button.tpl.html index 6edf9c76a0..5549fd35e6 100644 --- a/ui/src/app/components/timewindow-button.tpl.html +++ b/ui/src/app/components/timewindow-button.tpl.html @@ -15,7 +15,7 @@ limitations under the License. --> - + {{model.displayValue}} \ No newline at end of file diff --git a/ui/src/app/components/timewindow.directive.js b/ui/src/app/components/timewindow.directive.js index 0d06de8679..991a3838ff 100644 --- a/ui/src/app/components/timewindow.directive.js +++ b/ui/src/app/components/timewindow.directive.js @@ -97,7 +97,7 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM element.html(template); scope.openEditMode = function (event) { - if (scope.disabled) { + if (scope.timewindowDisabled) { return; } var position; @@ -212,6 +212,10 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM } } + scope.isTimewindowDisabled = function () { + return scope.disabled || (!scope.isEdit && scope.model.hideInterval && scope.model.hideAggregation && scope.model.hideAggInterval); + } + ngModelCtrl.$render = function () { scope.model = timeService.defaultTimewindow(); if (ngModelCtrl.$viewValue) { @@ -243,6 +247,7 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM model.hideAggregation = value.hideAggregation; model.hideAggInterval = value.hideAggInterval; } + scope.timewindowDisabled = scope.isTimewindowDisabled(); scope.updateDisplayValue(); }; diff --git a/ui/src/app/components/timewindow.tpl.html b/ui/src/app/components/timewindow.tpl.html index 0e0475b9cd..2889addd5a 100644 --- a/ui/src/app/components/timewindow.tpl.html +++ b/ui/src/app/components/timewindow.tpl.html @@ -16,7 +16,7 @@ -->
- + {{ 'timewindow.edit' | translate }} @@ -28,7 +28,7 @@ {{model.displayValue}} - + {{ 'timewindow.edit' | translate }} From a490f02a29eb28e07367a359d7c13a0e0a5229c7 Mon Sep 17 00:00:00 2001 From: Albert Yurgin <36601239+Scvoll@users.noreply.github.com> Date: Mon, 23 Dec 2019 18:36:29 +0300 Subject: [PATCH 28/46] fixed interpolation error (#2290) --- ui/src/app/locale/locale.constant-ru_RU.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/locale/locale.constant-ru_RU.json b/ui/src/app/locale/locale.constant-ru_RU.json index ca4570638a..41fa69a3dc 100644 --- a/ui/src/app/locale/locale.constant-ru_RU.json +++ b/ui/src/app/locale/locale.constant-ru_RU.json @@ -661,7 +661,7 @@ "delete-device-title": "Вы точно хотите удалить устройство '{{deviceName}}'?", "delete-device-text": "Внимание, после подтверждения устройство и все связанные с ним данные будут безвозвратно утеряны.", "delete-devices-title": "Вы точно хотите удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} }?", - "delete-devices-action-title": "Удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} } }", + "delete-devices-action-title": "Удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} }", "delete-devices-text": "Внимание, после подтверждения выбранные устройства и все связанные с ними данные будут безвозвратно утеряны..", "unassign-device-title": "Вы точно хотите отозвать устройство '{{deviceName}}'?", "unassign-device-text": "После подтверждения устройство будет недоступно клиенту.", From 7bdbdad287df96b2b5121b97c60af3ad8656c8a9 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 23 Dec 2019 17:46:48 +0200 Subject: [PATCH 29/46] upgrade from version 2.4.2 --- .../server/install/ThingsboardInstallService.java | 6 +++--- .../service/install/CassandraDatabaseUpgradeService.java | 2 +- .../server/service/install/SqlDatabaseUpgradeService.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) 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 744fb368a9..b58a2c42e5 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -123,10 +123,10 @@ public class ThingsboardInstallService { log.info("Upgrading ThingsBoard from version 2.4.1 to 2.4.2 ..."); databaseUpgradeService.upgradeDatabase("2.4.1"); - case "2.4.2.1": - log.info("Upgrading ThingsBoard from version 2.4.2.1 to 2.4.3 ..."); + case "2.4.2": + log.info("Upgrading ThingsBoard from version 2.4.2 to 2.4.3 ..."); - databaseUpgradeService.upgradeDatabase("2.4.2.1"); + databaseUpgradeService.upgradeDatabase("2.4.2"); log.info("Updating system data..."); diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java index 7d0b22db67..01fb0c083d 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java @@ -278,7 +278,7 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { } catch (InvalidQueryException e) {} log.info("Schema updated."); break; - case "2.4.2.1": + case "2.4.2": log.info("Updating schema ..."); String updateAlarmTableStmt = "alter table alarm add propagate_relation_types text"; try { 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 d686b172cf..b9e9504462 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 @@ -196,7 +196,7 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { log.info("Schema updated."); } break; - case "2.4.2.1": + case "2.4.2": try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { log.info("Updating schema ..."); try { From 0ef930e43aef3945b51857d1613057734a95fcd3 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 23 Dec 2019 18:28:46 +0200 Subject: [PATCH 30/46] Set version --- msa/js-executor/package.json | 2 +- msa/web-ui/package.json | 2 +- ui/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index 0cdafffef1..6e92570628 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "2.5.0", + "version": "2.3.0", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index 176791d65a..b66db7c2ac 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "2.5.0", + "version": "2.3.0", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/ui/package.json b/ui/package.json index 4c67341178..04ebcec1eb 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard", "private": true, - "version": "2.5.0", + "version": "2.3.0", "description": "ThingsBoard UI", "licenses": [ { From 10777861a0c60d164e18a34fc31039e97ab54c5c Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 23 Dec 2019 18:31:44 +0200 Subject: [PATCH 31/46] Set version --- msa/js-executor/package.json | 2 +- msa/web-ui/package.json | 2 +- ui/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index 6e92570628..c87b62c6eb 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "2.3.0", + "version": "2.4.3", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index b66db7c2ac..188084d375 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "2.3.0", + "version": "2.4.3", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/ui/package.json b/ui/package.json index 04ebcec1eb..f9f6083b31 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard", "private": true, - "version": "2.3.0", + "version": "2.4.3", "description": "ThingsBoard UI", "licenses": [ { From aa7c946cb835494a7b460c796d1bc9540354ceec Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Mon, 23 Dec 2019 18:41:49 +0200 Subject: [PATCH 32/46] Improvement/new datakey types (#2291) * Add support import label * Add translate tooltip --- ui/src/app/components/datasource-entity.tpl.html | 6 +++--- ui/src/app/locale/locale.constant-en_US.json | 1 + ui/src/app/locale/locale.constant-ru_RU.json | 1 + ui/src/app/locale/locale.constant-uk_UA.json | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ui/src/app/components/datasource-entity.tpl.html b/ui/src/app/components/datasource-entity.tpl.html index a167d313ee..df06e9465f 100644 --- a/ui/src/app/components/datasource-entity.tpl.html +++ b/ui/src/app/components/datasource-entity.tpl.html @@ -44,7 +44,7 @@ - {{'datakey.entityField' | translate }} + {{'datakey.entity-field' | translate }} @@ -65,7 +65,7 @@ - {{'datakey.entityField' | translate }} + {{'datakey.entity-field' | translate }} @@ -91,7 +91,7 @@ - {{'datakey.entityField' | translate }} + {{'datakey.entity-field' | translate }} diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 6310438128..f6a42cd957 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -583,6 +583,7 @@ "configuration": "Data key configuration", "timeseries": "Timeseries", "attributes": "Attributes", + "entity-field": "Entity field", "alarm": "Alarm fields", "timeseries-required": "Entity timeseries are required.", "timeseries-or-attributes-required": "Entity timeseries/attributes are required.", diff --git a/ui/src/app/locale/locale.constant-ru_RU.json b/ui/src/app/locale/locale.constant-ru_RU.json index 41fa69a3dc..25257232d0 100644 --- a/ui/src/app/locale/locale.constant-ru_RU.json +++ b/ui/src/app/locale/locale.constant-ru_RU.json @@ -583,6 +583,7 @@ "configuration": "Конфигурация ключа данных", "timeseries": "Телеметрия", "attributes": "Атрибуты", + "entity-field": "Поле объекта", "alarm": "Параметры оповещения", "timeseries-required": "Телеметрия объекта обязательна.", "timeseries-or-attributes-required": "Телеметрия/атрибуты обязательны.", diff --git a/ui/src/app/locale/locale.constant-uk_UA.json b/ui/src/app/locale/locale.constant-uk_UA.json index 49fd45a409..bc64b52901 100644 --- a/ui/src/app/locale/locale.constant-uk_UA.json +++ b/ui/src/app/locale/locale.constant-uk_UA.json @@ -699,6 +699,7 @@ "configuration": "Конфігурація ключа даних", "timeseries": "Телеметрія", "attributes": "Атрибути", + "entity-field": "Поле сутності", "alarm": "Поля сигнала тривоги", "timeseries-required": "Необхідно вказати Телеметрія.", "timeseries-or-attributes-required": "Необхідно вказати телеметрію/атрибути.", From 04f18a6fe8a30c66ada598a6503600e3d1afb8fd Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Tue, 24 Dec 2019 13:30:02 +0200 Subject: [PATCH 33/46] Bugs entityFields dataKey (#2293) * Add support import label * Fix not load and show first dataKey --- ui/src/app/api/entity.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index 51336ee374..b71fcfe75e 100644 --- a/ui/src/app/api/entity.service.js +++ b/ui/src/app/api/entity.service.js @@ -850,7 +850,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device function getEntityFieldKeys (entityType, searchText) { let entityFieldKeys = []; - let query = searchText.toLowerCase(); + let query = searchText ? searchText.toLowerCase() : ""; switch(entityType) { case types.entityType.user: entityFieldKeys.push(types.entityField.name.keyName); From 8d45f32d8d78b436f57de43f7bf2928724bf0399 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 24 Dec 2019 14:04:04 +0200 Subject: [PATCH 34/46] Improve entity state controller. --- .../states/entity-state-controller.js | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/ui/src/app/dashboard/states/entity-state-controller.js b/ui/src/app/dashboard/states/entity-state-controller.js index a4c6cb7d7c..4762af0942 100644 --- a/ui/src/app/dashboard/states/entity-state-controller.js +++ b/ui/src/app/dashboard/states/entity-state-controller.js @@ -44,8 +44,7 @@ export default function EntityStateController($scope, $timeout, $location, $stat function openState(id, params, openRightLayout) { if (vm.states && vm.states[id]) { resolveEntity(params).then( - function success(entityName) { - params.entityName = entityName; + function success() { var newState = { id: id, params: params @@ -66,8 +65,7 @@ export default function EntityStateController($scope, $timeout, $location, $stat } if (vm.states && vm.states[id]) { resolveEntity(params).then( - function success(entityName) { - params.entityName = entityName; + function success() { var newState = { id: id, params: params @@ -183,16 +181,16 @@ export default function EntityStateController($scope, $timeout, $location, $stat params = params[params.targetEntityParamName]; } if (params && params.entityId && params.entityId.id && params.entityId.entityType) { - if (params.entityName && params.entityName.length) { - deferred.resolve(params.entityName); + if (isEntityResolved(params)) { + deferred.resolve(); } else { entityService.getEntity(params.entityId.entityType, params.entityId.id, { ignoreLoading: true, ignoreErrors: true }).then( function success(entity) { - var entityName = entity.name; - deferred.resolve(entityName); + params.entityName = entity.name; + deferred.resolve(); }, function fail() { deferred.reject(); @@ -200,11 +198,18 @@ export default function EntityStateController($scope, $timeout, $location, $stat ); } } else { - deferred.resolve(''); + deferred.resolve(); } return deferred.promise; } + function isEntityResolved(params) { + if (!params.entityName || !params.entityName.length) { + return false; + } + return true; + } + function parseState(stateBase64) { var result; if (stateBase64) { From 981f7443ce9f3f0ea1ff3d582dd1a693e78da2c6 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 24 Dec 2019 14:23:35 +0200 Subject: [PATCH 35/46] Improve resolveAliasFilter method --- ui/src/app/api/entity.service.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index b71fcfe75e..7c656442f7 100644 --- a/ui/src/app/api/entity.service.js +++ b/ui/src/app/api/entity.service.js @@ -439,7 +439,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device return entityId; } - function getStateEntityId(filter, stateParams) { + function getStateEntityInfo(filter, stateParams) { var entityId = null; if (stateParams) { if (filter.stateEntityParamName && filter.stateEntityParamName.length) { @@ -456,7 +456,9 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device if (entityId) { entityId = resolveAliasEntityId(entityId.entityType, entityId.id); } - return entityId; + return { + entityId: entityId + }; } function resolveAliasFilter(filter, stateParams, maxItems, failOnEmpty) { @@ -468,7 +470,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device if (filter.stateEntityParamName && filter.stateEntityParamName.length) { result.entityParamName = filter.stateEntityParamName; } - var stateEntityId = getStateEntityId(filter, stateParams); + var stateEntityInfo = getStateEntityInfo(filter, stateParams); + var stateEntityId = stateEntityInfo.entityId; switch (filter.type) { case types.aliasFilterType.singleEntity.value: var aliasEntityId = resolveAliasEntityId(filter.singleEntity.entityType, filter.singleEntity.id); From 45a4c6f3423b7271d7f7e1b4dca95fd6fcdc1aab Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Tue, 24 Dec 2019 16:17:01 +0200 Subject: [PATCH 36/46] Improvement/state entity name (#2294) * Add support import label * Change enityName use targetEntityParam --- ui/src/app/dashboard/states/entity-state-controller.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/src/app/dashboard/states/entity-state-controller.js b/ui/src/app/dashboard/states/entity-state-controller.js index 4762af0942..b5f9762708 100644 --- a/ui/src/app/dashboard/states/entity-state-controller.js +++ b/ui/src/app/dashboard/states/entity-state-controller.js @@ -164,7 +164,12 @@ export default function EntityStateController($scope, $timeout, $location, $stat var stateName = vm.states[vm.stateObject[index].id].name; stateName = utils.customTranslation(stateName, stateName); var params = vm.stateObject[index].params; - var entityName = params && params.entityName ? params.entityName : ''; + var entityName; + if (params && params.targetEntityParamName && params[params.targetEntityParamName].entityName) { + entityName = params[params.targetEntityParamName].entityName; + } else { + entityName = params && params.entityName ? params.entityName : ''; + } result = utils.insertVariable(stateName, 'entityName', entityName); for (var prop in params) { if (params[prop] && params[prop].entityName) { From 92c1374a3f31a31b9492a192d65a740b67352c16 Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Thu, 26 Dec 2019 17:53:10 +0200 Subject: [PATCH 37/46] Fix knob control widget (#2298) * Add support import label * Fix knob control widget --- ui/src/app/app.run.js | 2 -- ui/src/app/widget/lib/rpc/knob.directive.js | 5 ++++- ui/src/app/widget/lib/rpc/knob.tpl.html | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/src/app/app.run.js b/ui/src/app/app.run.js index 5bb8131e1e..0ca44316c1 100644 --- a/ui/src/app/app.run.js +++ b/ui/src/app/app.run.js @@ -162,14 +162,12 @@ export default function AppRun($rootScope, $window, $injector, $location, $log, if (forbiddenDialog === null) { $translate(['access.access-forbidden', 'access.access-forbidden-text', - 'access.access-forbidden', 'action.cancel', 'action.sign-in']).then(function (translations) { if (forbiddenDialog === null) { forbiddenDialog = $mdDialog.confirm() .title(translations['access.access-forbidden']) .htmlContent(translations['access.access-forbidden-text']) - .ariaLabel(translations['access.access-forbidden']) .cancel(translations['action.cancel']) .ok(translations['action.sign-in']); $mdDialog.show(forbiddenDialog).then(function () { diff --git a/ui/src/app/widget/lib/rpc/knob.directive.js b/ui/src/app/widget/lib/rpc/knob.directive.js index 4bd4a58288..d26e4a8d09 100644 --- a/ui/src/app/widget/lib/rpc/knob.directive.js +++ b/ui/src/app/widget/lib/rpc/knob.directive.js @@ -328,6 +328,9 @@ function KnobController($element, $scope, $document) { var textWidth = measureTextWidth(text, fontSize); while (textWidth > maxWidth) { fontSize--; + if (fontSize < 0) { + break; + } textWidth = measureTextWidth(text, fontSize); } element.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'}); @@ -335,7 +338,7 @@ function KnobController($element, $scope, $document) { function measureTextWidth(text, fontSize) { textMeasure.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'}); - textMeasure.text(text); + textMeasure.html(text); return textMeasure.width(); } diff --git a/ui/src/app/widget/lib/rpc/knob.tpl.html b/ui/src/app/widget/lib/rpc/knob.tpl.html index 290b1920a7..45cc766302 100644 --- a/ui/src/app/widget/lib/rpc/knob.tpl.html +++ b/ui/src/app/widget/lib/rpc/knob.tpl.html @@ -29,7 +29,7 @@
- {{ vm.error }} +
{{ vm.title }} @@ -42,4 +42,4 @@
- \ No newline at end of file + From 41a1c6679fb147f6f2442cb7a4563e37ea8c7073 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 27 Dec 2019 18:06:31 +0200 Subject: [PATCH 38/46] Added support entity Label to state name and breadcrumb for dashboard --- ui/src/app/api/subscription.js | 8 ++++--- .../components/widget/widget.controller.js | 15 ++++++++---- .../states/entity-state-controller.js | 23 +++++++++++-------- .../app/widget/lib/entities-table-widget.js | 12 +++++----- ui/src/app/widget/lib/flot-widget.js | 3 ++- ui/src/app/widget/lib/map-widget2.js | 9 +++++--- .../app/widget/lib/timeseries-table-widget.js | 10 ++++---- 7 files changed, 49 insertions(+), 31 deletions(-) diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js index 86ab823294..f3d8e5cf47 100644 --- a/ui/src/app/api/subscription.js +++ b/ui/src/app/api/subscription.js @@ -179,8 +179,7 @@ export default class Subscription { } getFirstEntityInfo() { - var entityId; - var entityName; + var entityId, entityName, entityLabel = null; if (this.type === this.ctx.types.widgetType.rpc.value) { if (this.targetDeviceId) { entityId = { @@ -196,6 +195,7 @@ export default class Subscription { id: this.alarmSource.entityId }; entityName = this.alarmSource.entityName; + entityLabel = this.alarmSource.entityLabel; } } else { for (var i=0;i Date: Mon, 6 Jan 2020 16:35:48 +0200 Subject: [PATCH 39/46] Fix: Add entityLabel to handleWidgetAction --- ui/src/app/components/widget/widget.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/components/widget/widget.controller.js b/ui/src/app/components/widget/widget.controller.js index d093e0c1bd..b9f1317528 100644 --- a/ui/src/app/components/widget/widget.controller.js +++ b/ui/src/app/components/widget/widget.controller.js @@ -490,7 +490,7 @@ export default function WidgetController($scope, $state, $timeout, $window, $ocL } } - function handleWidgetAction($event, descriptor, entityId, entityName, additionalParams) { + function handleWidgetAction($event, descriptor, entityId, entityName, additionalParams, entityLabel) { var type = descriptor.type; var targetEntityParamName = descriptor.stateEntityParamName; var targetEntityId; From 168f0d64813b7bea4b343beaaef3ee2c59c97ce9 Mon Sep 17 00:00:00 2001 From: Li-Heng Yu <007seadog@gmail.com> Date: Mon, 6 Jan 2020 22:39:04 +0800 Subject: [PATCH 40/46] Added Traditional Chinese Interface for Web UI (#2303) * Fixed other languages name in zh_CN ui * Added Traditional Chinese for UI * Added language name of Traditional Chinese for en_US pack * Fixed zh_TW language pack and updated language usage --- ui/src/app/locale/locale.constant-en_US.json | 3 +- ui/src/app/locale/locale.constant-zh_CN.json | 27 +- ui/src/app/locale/locale.constant-zh_TW.json | 1622 ++++++++++++++++++ 3 files changed, 1638 insertions(+), 14 deletions(-) create mode 100644 ui/src/app/locale/locale.constant-zh_TW.json diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index f6a42cd957..dde68c35b4 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -1794,7 +1794,8 @@ "locales": { "de_DE": "German", "fr_FR": "French", - "zh_CN": "Chinese", + "zh_CN": "Simplified Chinese", + "zh_TW": "Traditional Chinese", "en_US": "English", "it_IT": "Italian", "ko_KR": "Korean", diff --git a/ui/src/app/locale/locale.constant-zh_CN.json b/ui/src/app/locale/locale.constant-zh_CN.json index a7f1cb9e62..0c1f5f743b 100644 --- a/ui/src/app/locale/locale.constant-zh_CN.json +++ b/ui/src/app/locale/locale.constant-zh_CN.json @@ -1603,19 +1603,20 @@ "language": { "language": "语言", "locales": { - "de_DE": "德语", - "en_US": "英语", - "fr_FR": "法国", - "ko_KR": "韩语", - "zh_CN": "汉语", - "ru_RU": "俄语", - "es_ES": "西班牙语", - "it_IT": "意大利", - "ja_JA": "日本", - "tr_TR": "土耳其", - "fa_IR": "波斯语", - "uk_UA": "乌克兰", - "cs_CZ": "在捷克" + "de_DE": "德文", + "en_US": "英文", + "fr_FR": "法文", + "ko_KR": "韩文", + "zh_CN": "简体中文", + "zh_TW": "繁体中文", + "ru_RU": "俄文", + "es_ES": "西班牙文", + "it_IT": "意大利文", + "ja_JA": "日文", + "tr_TR": "土耳其文", + "fa_IR": "波斯文", + "uk_UA": "乌克兰文", + "cs_CZ": "捷克文" } } } diff --git a/ui/src/app/locale/locale.constant-zh_TW.json b/ui/src/app/locale/locale.constant-zh_TW.json new file mode 100644 index 0000000000..acaa9ac53c --- /dev/null +++ b/ui/src/app/locale/locale.constant-zh_TW.json @@ -0,0 +1,1622 @@ +{ +    "access": { +        "unauthorized": "未授權", +        "unauthorized-access": "未授權存取", +        "unauthorized-access-text": "您需要登入才能存取這個資源!", +        "access-forbidden": "禁止存取", +        "access-forbidden-text": "您沒有存取此位置的權限
如果您仍希望存取此位置,請嘗試使用其他用戶登入。", +        "refresh-token-expired": "Session 已過期", +        "refresh-token-failed": "無法更新 Session" +    }, +    "action": { +        "activate": "啟動", +        "suspend": "暫停", +        "save": "儲存", +        "saveAs": "另存為", +        "cancel": "取消", +        "ok": "確定", +        "delete": "刪除", +        "add": "增加", +        "yes": "是", +        "no": "否", +        "update": "更新", +        "remove": "移除", +        "search": "查詢", +        "clear-search": "清除查詢", +        "assign": "分配", +        "unassign": "取消分配", +        "share": "分享", +        "make-private": "私有", +        "apply": "應用", +        "apply-changes": "應用更改", +        "edit-mode": "編輯模式", +        "enter-edit-mode": "進入編輯模式", +        "decline-changes": "取消更改", +        "close": "關閉", +        "back": "返回", +        "run": "執行", +        "sign-in": "登入!", +        "edit": "編輯", +        "view": "查看", +        "create": "建立", +        "drag": "拖拉", +        "refresh": "更新", +        "undo": "取消", +        "copy": "複製", +        "paste": "貼上", +        "copy-reference": "複製引用", +        "paste-reference": "貼上引用", +        "import": "匯入", +        "export": "匯出", +        "share-via": "通過 {{provider}}分享" +    }, +    "aggregation": { +        "aggregation": "聚合", +        "function": "資料聚合功能", +        "limit": "最大值", +        "group-interval": "分組間隔", +        "min": "最少值", +        "max": "最大值", +        "avg": "平均值", +        "sum": "總計", +        "count": "Count", +        "none": "空" +    }, +    "admin": { +        "general": "一般", +        "general-settings": "一般設定", +        "outgoing-mail": "發送郵件", +        "outgoing-mail-settings": "發送郵件設定", +        "system-settings": "系統設定", +        "test-mail-sent": "測試郵件發送成功!", +        "base-url": "基本URL", +        "base-url-required": "基本URL必填。", +        "mail-from": "郵件來自", +        "mail-from-required": "郵件發件人必填。", +        "smtp-protocol": "SMTP協定", +        "smtp-host": "SMTP主機", +        "smtp-host-required": "SMTP主機必填。", +        "smtp-port": "SMTP連接埠", +        "smtp-port-required": "您必須提供一個smtp連接埠。", +        "smtp-port-invalid": "這看起來不是有效的smtp連接埠。", +        "timeout-msec": "超時(ms)", +        "timeout-required": "超時必填。", +        "timeout-invalid": "這看起來不像有效的超時值。", +        "enable-tls": "啟用TLS", +        "send-test-mail": "發送測試郵件" +    }, +    "alarm": { +        "alarm": "警告", +        "alarms": "警告", +        "select-alarm": "選擇警告", +        "no-alarms-matching": "沒有找到符合 '{{entity}}' 的警告", +        "alarm-required": "警告必填", +        "alarm-status": "警告狀態", +        "search-status": { +            "ANY": "所有", +            "ACTIVE": "已啟動", +            "CLEARED": "已清除", +            "ACK": "已回覆", +            "UNACK": "未回覆" +        }, +        "display-status": { +            "ACTIVE_UNACK": "啟動未回覆", +            "ACTIVE_ACK": "啟動已回覆", +            "CLEARED_UNACK": "清除未回覆", +            "CLEARED_ACK": "清除已回覆" +        }, +        "no-alarms-prompt": "未發現警告", +        "created-time": "建立時間", +        "type": "類型", +        "severity": "嚴重程度", +        "originator": "起因", +        "originator-type": "起因類型", +        "details": "詳細資訊", +        "status": "狀態", +        "alarm-details": "警告詳細資訊", +        "start-time": "開始時間", +        "end-time": "結束時間", +        "ack-time": "回覆時間", +        "clear-time": "建立時間", +        "severity-critical": "危險", +        "severity-major": "重要", +        "severity-minor": "次要", +        "severity-warning": "警告", +        "severity-indeterminate": "不確定", +        "acknowledge": "回覆", +        "clear": "清除", +        "search": "搜尋警告", +        "selected-alarms": "已選擇 { count, plural, 1 {1 警告} other {# 警告} } ", +        "no-data": "無資料顯示", +        "polling-interval": "警告輪詢間隔(秒)", +        "polling-interval-required": "警告輪詢間隔必填。", +        "min-polling-interval-message": "輪詢間隔至少是1秒。", +        "aknowledge-alarms-title": "回覆 { count, plural, 1 {1 警告} other {# 警告} }", +        "aknowledge-alarms-text": "確定要回覆 { count, plural, 1 {1 警告} other {# 警告} }?", +        "clear-alarms-title": "清除 { count, plural, 1 {1 警告} other {# 警告} }", +        "clear-alarms-text": "確定要清除 { count, plural, 1 {1 警告} other {# 警告} }?" +    }, +    "alias": { +        "add": "增加別名", +        "edit": "編輯別名", +        "name": "別名", +        "name-required": "別名必填", +        "duplicate-alias": "別名已經存在。", +        "filter-type-single-entity": "單一實體", +        "filter-type-entity-list": "實體列表", +        "filter-type-entity-name": "實體名稱", +        "filter-type-state-entity": "實體(儀表板狀態)", +        "filter-type-state-entity-description": "實體令牌(儀表板狀態參數)", +        "filter-type-asset-type": "資產類型", +        "filter-type-asset-type-description": "類型為 '{{assetType}}' 的資產", +        "filter-type-asset-type-and-name-description": "類型為 '{{assetType}}' 且以 '{{prefix}}' 開頭的資產", +        "filter-type-device-type": "設備類型", +        "filter-type-device-type-description": "類型為 '{{deviceType}}' 的設備", + "filter-type-device-type-and-name-description": "類型為 '{{deviceType}}' 且以 '{{prefix}}' 開頭的設備", +        "filter-type-entity-view-type": "實體視圖類型", +        "filter-type-entity-view-type-description": "類型為 '{{entityView}}' 的實體視圖", +        "filter-type-entity-view-type-and-name-description": "類型為 {{entityView}}' 且以 '{{prefix}}' 開頭的實體視圖", +        "filter-type-relations-query": "關係查詢", +        "filter-type-relations-query-description": "具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的 {{entities}} ", +        "filter-type-asset-search-query": "資產搜尋查詢", +        "filter-type-asset-search-query-description": "類型為 {{assetTypes}} 且具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的資產", +        "filter-type-device-search-query": "設備搜尋查詢", +        "filter-type-device-search-query-description": "類型為 {{deviceTypes}} 且具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的設備", +        "filter-type-entity-view-search-query": "實體視圖搜尋查詢", +        "filter-type-entity-view-search-query-description": "類型為 {{entityViewTypes}} 且具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的實體視圖", +        "entity-filter": "實體過濾", +        "resolve-multiple": "解決為多實體", +        "filter-type": "過濾類型", +        "filter-type-required": "過濾類型必填。", +        "entity-filter-no-entity-matched": "未找到符合指定過濾條件的實體。", +        "no-entity-filter-specified": "沒有指定實體過濾條件", +        "root-state-entity": "使用儀表板狀態實體作為根實體", +        "root-entity": "根實體", +        "state-entity-parameter-name": "狀態實體參數名稱", +        "default-state-entity": "預設狀態實體", +        "default-entity-parameter-name": "預設", +        "max-relation-level": "最大關係層級", +        "unlimited-level": "不限層級", +        "state-entity": "儀表板狀態實體", +        "all-entities": "所有實體", +        "any-relation": "不限" +    }, +    "asset": { +        "asset": "資產", +        "assets": "資產", +        "management": "資產管理", +        "view-assets": "查看資產", +        "add": "增加資產", +        "assign-to-customer": "分配給客戶", +        "assign-asset-to-customer": "將資產分配給客戶", +        "assign-asset-to-customer-text": "請選擇要分配給客戶的資產", +        "no-assets-text": "未找到資產", +        "assign-to-customer-text": "請選擇客戶以分配資產", +        "public": "公開", +        "assignedToCustomer": "分配客戶", +        "make-public": "資產設為公開", +        "make-private": "資產設為私有", +        "unassign-from-customer": "取消分配客戶", +        "delete": "刪除資產", +        "asset-public": "資產公開", +        "asset-type": "資產類型", +        "asset-type-required": "資產類型必填。", +        "select-asset-type": "選擇資產類型", +        "enter-asset-type": "輸入資產類型", +        "any-asset": "任何資產", +        "no-asset-types-matching": "沒有找到符合 '{{entitySubtype}}' 的資產類型。", +        "asset-type-list-empty": "資產類型未選擇。", +        "asset-types": "資產類型", +        "name": "名稱", +        "name-required": "名稱必填。", +        "description": "描述", +        "type": "類型", +        "type-required": "類型必填。", +        "details": "詳細資訊", +        "events": "事件", +        "add-asset-text": "增加新資產", +        "asset-details": "資產詳細資訊", +        "assign-assets": "分配資產", +        "assign-assets-text": "分配 { count, plural, 1 {1 資產} other {# 資產} } 給客戶", +        "delete-assets": "刪除資產", +        "unassign-assets": "取消分配資產", +        "unassign-assets-action-title": "從客戶處取消分配 { count, plural, 1 {1 資產} other {# 資產} } ", +        "assign-new-asset": "分配新資產", +        "delete-asset-title": "確定要刪除資產 '{{assetName}}'?", +        "delete-asset-text": "小心!確認後資產及其所有相關資料將無法恢復。", +        "delete-assets-title": "確定要刪除 { count, plural, 1 {1 資產} other {# 資產} }?", +        "delete-assets-action-title": "刪除 { count, plural, 1 {1 資產} other {# 資產} }", +        "delete-assets-text": "小心,確認後,所有選擇的資產將被刪除,所有相關的資料將變得無法恢復。", +        "make-public-asset-title": "你確定你想建立公開'{{assetName}}'資產?", +        "make-public-asset-text": "確認後,資產及其所有資料將被公開並被他人存取。", +        "make-private-asset-title": "你確定你想建立私有 '{{assetName}}' 資產?", +        "make-private-asset-text": "確認後,資產及其所有資料將被私有化,無法被他人存取。", +        "unassign-asset-title": "您確定要取消對'{{assetName}}'資產的分配嗎?", +        "unassign-asset-text": "確認後,資產將未分配,客戶無法存取。", +        "unassign-asset": "未分配資產", +        "unassign-assets-title": "您確定要取消分配 { count, plural, 1 {1 資產} other {# 資產} }嗎?", +        "unassign-assets-text": "確認後,所有選擇的資產將被分配,客戶無法存取。", +        "copyId": "複製資產ID", +        "idCopiedMessage": "資產ID已經複製到剪貼簿", +        "select-asset": "選擇資產", +        "no-assets-matching": "沒有找到符合 '{{entity}}' 的資產。", +        "asset-required": "資產必填", +        "name-starts-with": "資產名稱以此開頭", +        "label": "標籤" +    }, +    "attribute": { +        "attributes": "屬性", +        "latest-telemetry": "最新遙測", +        "attributes-scope": "設備屬性範圍", +        "scope-latest-telemetry": "最新遙測", +        "scope-client": "客戶端屬性", +        "scope-server": "服務端屬性", +        "scope-shared": "共享屬性", +        "add": "增加屬性", +        "key": "鍵", +        "last-update-time": "最後更新時間", +        "key-required": "屬性鍵必填。", +        "value": "值", +        "value-required": "屬性值必填。", +        "delete-attributes-title": "您確定要刪除 { count, plural, 1 {1 屬性} other {# 屬性} }嗎?", +        "delete-attributes-text": "注意,確認後所有選中的屬性都會被刪除。", + "delete-attributes": "刪除屬性", +        "enter-attribute-value": "輸入屬性值", +        "show-on-widget": "在部件上顯示", +        "widget-mode": "部件模式", +        "next-widget": "下一個部件", +        "prev-widget": "上一個部件", +        "add-to-dashboard": "增加到儀表板", +        "add-widget-to-dashboard": "將部件增加到儀表板", +        "selected-attributes": "{ count, plural, 1 {1 屬性} other {# 屬性} } 被選中", +        "selected-telemetry": "{ count, plural, 1 {1 遙測} other {# 遙測} } 被選中" +    }, +    "audit-log": { +        "audit": "審計", +        "audit-logs": "審計日誌", +        "timestamp": "時間戳", +        "entity-type": "實體類型", +        "entity-name": "實體名稱", +        "user": "用戶", +        "type": "類型", +        "status": "狀態", +        "details": "詳細資訊", +        "type-added": "增加", +        "type-deleted": "刪除", +        "type-updated": "更新", +        "type-attributes-updated": "更新屬性", +        "type-attributes-deleted": "刪除屬性", +        "type-rpc-call": "RPC調用", +        "type-credentials-updated": "更新憑證", +        "type-assigned-to-customer": "分配給客戶", +        "type-unassigned-from-customer": "未分配給客戶", +        "type-activated": "啟動", +        "type-suspended": "暫停", +        "type-credentials-read": "讀取憑證", +        "type-attributes-read": "讀取屬性", +        "status-success": "成功", +        "status-failure": "失敗", +        "audit-log-details": "審計日誌詳細資訊", +        "no-audit-logs-prompt": "找不到日誌", +        "action-data": "活動資料", +        "failure-details": "失敗詳細資訊", +        "search": "查找審計日誌", +        "clear-search": "清空查找" +    }, + "confirm-on-exit": { +        "message": "您有未儲存的更改。確定要離開此頁嗎?", +        "html-message": "您有未儲存的更改。
確定要離開此頁面嗎?", +        "title": "未儲存的更改" +    }, +    "contact": { +        "country": "國家", +        "city": "城市", +        "state": "州", +        "postal-code": "郵政編碼", +        "postal-code-invalid": "只允許數字。", +        "address": "地址", +        "address2": "地址2", +        "phone": "手機", +        "email": "郵箱", +        "no-address": "無地址" +    }, +    "common": { +        "username": "用戶名", +        "password": "密碼", +        "enter-username": "輸入用戶名", +        "enter-password": "輸入密碼", +        "enter-search": "輸入檢索條件" +    }, +    "content-type": { +        "json": "Json", +        "text": "Text", +        "binary": "Binary (Base64)" +    }, +    "customer": { +        "customer": "客戶", +        "customers": "客戶", +        "management": "客戶管理", +        "dashboard": "客戶儀表板", +        "dashboards": "客戶儀表板", +        "devices": "客戶設備", +        "entity-views": "客戶實體視圖", +        "assets": "客戶資產", +        "public-dashboards": "公共儀表板", +        "public-devices": "公共設備", +        "public-assets": "公共資產", +        "public-entity-views": "公共實體視圖", +        "add": "增加客戶", +        "delete": "刪除客戶", +        "manage-customer-users": "管理客戶用戶", +        "manage-customer-devices": "管理客戶設備", +        "manage-customer-dashboards": "管理客戶儀表板", +        "manage-public-devices": "管理公共設備", +        "manage-public-dashboards": "管理公共儀表板", +        "manage-customer-assets": "管理客戶資產", +        "manage-public-assets": "管理公共資產", +        "add-customer-text": "增加新客戶", +        "no-customers-text": "沒有找到客戶", +        "customer-details": "客戶詳細資訊", +        "delete-customer-title": "您確定要刪除客戶'{{customerTitle}}'嗎?", +        "delete-customer-text": "小心!確認後,客戶及其所有相關資料將無法恢復。", +        "delete-customers-title": "您確定要刪除 { count, plural, 1 {1 客戶} other {# 客戶} }嗎?", +        "delete-customers-action-title": "刪除 { count, plural, 1 {1 客戶} other {# 客戶} }", +        "delete-customers-text": "小心!確認後,所有選擇的客戶將被刪除,所有相關資料將無法恢復。", +        "manage-users": "管理用戶", +        "manage-assets": "管理資產", +        "manage-devices": "管理設備", +        "manage-dashboards": "管理儀表板", +        "title": "標題", +        "title-required": "需要標題", +        "description": "描述", +        "details": "詳細資訊", +        "events": "事件", +        "copyId": "複製客戶ID", +        "idCopiedMessage": "客戶ID已複製到剪貼板", +        "select-customer": "選擇客戶", +        "no-customers-matching": "沒有找到符合 '{{entity}}' 的客戶。", +        "customer-required": "客戶是必選項", +        "select-default-customer": "選擇預設的客戶", +        "default-customer": "預設客戶", +        "default-customer-required": "為了測試租戶級別上的儀表板,需要預設客戶。" +    }, + "datetime": { + "date-from": "日期從", + "time-from": "時間從", + "date-to": "日期到", + "time-to": "時間到" + }, + "dashboard": { +        "dashboard": "儀表板", +        "dashboards": "儀表板庫", +        "management": "儀表板管理", +        "view-dashboards": "查看儀表板", +        "add": "增加儀表板", +        "assign-dashboard-to-customer": "將儀表板分配給客戶", +        "assign-dashboard-to-customer-text": "請選擇要分配給客戶的儀表板", +        "assign-to-customer-text": "請選擇客戶分配儀表板", +        "assign-to-customer": "分配給客戶", +        "unassign-from-customer": "取消分配客戶", +        "make-public": "儀表板設為公開", +        "make-private": "儀表板設為私有", +        "manage-assigned-customers": "管理已分配的客戶", +        "assigned-customers": "已分配的客戶", +        "assign-to-customers": "將儀表板分配給客戶", +        "assign-to-customers-text": "請選擇客戶指定儀表板", +        "unassign-from-customers": "客戶未分配儀表板", +        "unassign-from-customers-text": "請選擇從儀表板中取消分配的客戶", +        "no-dashboards-text": "沒有找到儀表板", +        "no-widgets": "沒有配置部件", +        "add-widget": "增加新的部件", +        "title": "標題", +        "select-widget-title": "選擇部件", +        "select-widget-subtitle": "可用的部件類型列表", +        "delete": "刪除儀表板", +        "title-required": "需要標題。", +        "description": "描述", +        "details": "詳細資訊", +        "dashboard-details": "儀表板詳細資訊", +        "add-dashboard-text": "增加新的儀表板", +        "assign-dashboards": "分配儀表板", +        "assign-new-dashboard": "分配新的儀表板", +        "assign-dashboards-text": "分配 { count, plural, 1 {1 儀表板} other {# 儀表板} } 給客戶", +        "unassign-dashboards-action-text": "未分配 { count, plural, 1 {1 儀表板} other {# 儀表板} } 給客戶", +        "delete-dashboards": "刪除儀表板", +        "unassign-dashboards": "取消分配儀表板", + "unassign-dashboards-action-title": "從客戶處取消分配 { count, plural, 1 {1 儀表板} other {# 儀表板} } ", +        "delete-dashboard-title": "您確定要刪除儀表板 '{{dashboardTitle}}'嗎?", +        "delete-dashboard-text": "小心!確認後儀表板及其所有相關資料將無法恢復。", +        "delete-dashboards-title": "你確定你要刪除 { count, plural, 1 {1 儀表板} other {# 儀表板} }嗎?", +        "delete-dashboards-action-title": "刪除 { count, plural, 1 {1 儀表板} other {# 儀表板} }", +        "delete-dashboards-text": "小心!確認後所有選擇的儀表板將被刪除,所有相關資料將無法恢復。", +        "unassign-dashboard-title": "您確定要取消分配儀表板 '{{dashboardTitle}}'嗎?", +        "unassign-dashboard-text": "確認後,面板將被取消分配,客戶將無法存取。", +        "unassign-dashboard": "取消分配儀表板", +        "unassign-dashboards-title": "您確定要取消分配儀表板 { count, plural, 1 {1 儀表板} other {# 儀表板} } 嗎?", +        "unassign-dashboards-text": "確認後,所有選擇的儀表板將被取消分配,客戶將無法存取。", +        "public-dashboard-title": "儀表板現已公佈", +        "public-dashboard-text": "你的儀表板{{dashboardTitle}} 已被公開,可通過如下連結存取:", +        "public-dashboard-notice": "提示: 不要忘記將相關設備公開以存取其資料。", +        "make-private-dashboard-title": "您確定要將儀表板 '{{dashboardTitle}}' 設為私有嗎?", +        "make-private-dashboard-text": "確認後,儀表板將被設為私有,不能被其他人存取。", +        "make-private-dashboard": "儀表板設為私有", +        "socialshare-text": "'{{dashboardTitle}}' 由Thingsboard提供支持", +        "socialshare-title": "'{{dashboardTitle}}' 由Thingsboard提供支持", +        "select-dashboard": "選擇儀表板", +        "no-dashboards-matching": "找不到符合 '{{entity}}' 的儀表板。", +        "dashboard-required": "儀表板必填。", +        "select-existing": "選擇現有儀表板", +        "create-new": "建立新的儀表板", +        "new-dashboard-title": "新儀表板標題", +        "open-dashboard": "打開儀表板", +        "set-background": "設定背景", +        "background-color": "背景顏色", +        "background-image": "背景圖片", +        "background-size-mode": "背景大小模式", +        "no-image": "無圖像選擇", + "drop-image": "拖拉圖像或單擊以選擇要上傳的文件。", +        "settings": "設定", +        "columns-count": "列數", +        "columns-count-required": "需要列數。", +        "min-columns-count-message": "只允許最少10列", +        "max-columns-count-message": "只允許最多1000列", +        "widgets-margins": "部件間邊距", +        "horizontal-margin": "水平邊距", +        "horizontal-margin-required": "需要水平邊距值。", +        "min-horizontal-margin-message": "只允許0作為最小水平邊距值。", +        "max-horizontal-margin-message": "只允許50作為最大水平邊距值。", +        "vertical-margin": "垂直邊距", +        "vertical-margin-required": "需要垂直邊距值。", +        "min-vertical-margin-message": "只允許0作為最小垂直邊距值。", +        "max-vertical-margin-message": "只允許50作為最大垂直邊距值。", +        "autofill-height": "自動填充佈局高度", +        "mobile-layout": "移動端佈局設定", +        "mobile-row-height": "移動端行高距(px)", +        "mobile-row-height-required": "移動端行高距必填。", +        "min-mobile-row-height-message": "移動端行高距至少5px。", +        "max-mobile-row-height-message": "移動端行高距最多200px。", +        "display-title": "顯示儀表板標題", +        "toolbar-always-open": "工具欄常駐", +        "title-color": "標題顏色", +        "display-dashboards-selection": "顯示儀表板選項", +        "display-entities-selection": "顯示實體選項", +        "display-dashboard-timewindow": "顯示時間窗口", +        "display-dashboard-export": "顯示匯出", +        "import": "匯入儀表板", +        "export": "匯出儀表板", +        "export-failed-error": "無法匯出儀表板: {{error}}", +        "create-new-dashboard": "建立新的儀表板", +        "dashboard-file": "儀表板文件", +        "invalid-dashboard-file-error": "無法匯入儀表板: 儀表板資料結構無效。", +        "dashboard-import-missing-aliases-title": "配置匯入儀表板使用的別名", +        "create-new-widget": "建立新部件", +        "import-widget": "匯入部件", +        "widget-file": "部件文件", + "invalid-widget-file-error": "無法匯入窗口部件: 窗口部件資料結構無效。", +        "widget-import-missing-aliases-title": "配置匯入的窗口部件使用的別名", +        "open-toolbar": "打開儀表板工具欄", +        "close-toolbar": "關閉工具欄", +        "configuration-error": "配置錯誤", +        "alias-resolution-error-title": "儀表板別名配置錯誤", +        "invalid-aliases-config": "無法找到與某些別名過濾器符合的任何設備。
請聯繫您的管理員以解決此問題。", +        "select-devices": "選擇設備", +        "assignedToCustomer": "分配給客戶", +        "public": "公共", +        "public-link": "公共連結", +        "copy-public-link": "複製公共連結", +        "public-link-copied-message": "儀表板的公共連結已被複製到剪貼板", +        "manage-states": "儀表板狀態管理", +        "states": "儀表板狀態", +        "search-states": "儀表板狀態檢索", +        "selected-states": "{ count, plural, 1 {1 儀表板狀態} other {# 儀表板狀態} } 選中", +        "edit-state": "儀表板狀態編輯", +        "delete-state": "刪除儀表板狀態", +        "add-state": "增加儀表板狀態", +        "state": "儀表板狀態", +        "state-name": "狀態名", +        "state-name-required": "儀表板狀態名必填。", +        "state-id": "狀態ID", +        "state-id-required": "儀表板狀態ID必填。", +        "state-id-exists": "儀表板狀態ID已經存在。", +        "is-root-state": "根狀態", +        "delete-state-title": "刪除儀表板狀態", +        "delete-state-text": "確定要刪除儀表板狀態 '{{stateName}}' 嗎?", +        "show-details": "顯示詳細資訊", +        "hide-details": "隱藏詳細資訊", +        "select-state": "選擇目標狀態", +        "state-controller": "狀態控制" + }, + "datakey": { +        "settings": "設定", +        "advanced": "進階", +        "label": "標籤", +        "color": "顏色", +        "units": "單位符號", +        "decimals": "小數位數", +        "data-generation-func": "資料生成功能", +        "use-data-post-processing-func": "使用資料後處理功能", +        "configuration": "資料鍵配置", +        "timeseries": "時間序列", +        "attributes": "屬性", +        "alarm": "報警字段", +        "timeseries-required": "需要設備時間序列。", +        "timeseries-or-attributes-required": "設備時間/屬性必填。", +        "maximum-timeseries-or-attributes": "最大允許 { count, plural, 1 {1 時間序列/屬性} other {# 時間序列/屬性} }", +        "alarm-fields-required": "警告字段必填。", +        "function-types": "函數類型", +        "function-types-required": "需要函數類型。", +        "maximum-function-types": "至少需要 { count, plural, 1 {1 函數類型} other {# 函數類型} }" +    }, + "datasource": { +        "type": "資料源類型", +        "name": "資料源名稱", +        "add-datasource-prompt": "請增加資料源" +    }, +    "details": { +        "edit-mode": "編輯模式", +        "toggle-edit-mode": "切換編輯模式" +    }, +    "device": { +        "device": "設備", +        "device-required": "設備必填", +        "devices": "設備", +        "management": "設備管理", +        "view-devices": "查看設備", +        "device-alias": "設備別名", +        "aliases": "設備別名", +        "no-alias-matching": "'{{alias}}' 沒有找到。", +        "no-aliases-found": "找不到別名。", +        "no-key-matching": "'{{key}}' 沒有找到。", +        "no-keys-found": "找不到密鑰。", +        "create-new-alias": "建立一個新的!", +        "create-new-key": "建立一個新的!", +        "duplicate-alias-error": "找到重複別名 '{{alias}}'。
設備別名必須是唯一的。", +        "configure-alias": "配置 '{{alias}}' 別名", +        "no-devices-matching": "找不到與 '{{entity}}' 符合的設備。", +        "alias": "別名", +        "alias-required": "需要設備別名。", +        "remove-alias": "刪除設備別名", +        "add-alias": "增加設備別名", + "name-starts-with": "名稱前綴", +        "device-list": "設備列表", +        "use-device-name-filter": "使用過濾器", +        "device-list-empty": "沒有被選中的設備", +        "device-name-filter-required": "設備名稱過濾器必填。", +        "device-name-filter-no-device-matched": "找不到以'{{device}}' 開頭的設備。", +        "add": "增加設備", +        "assign-to-customer": "分配給客戶", +        "assign-device-to-customer": "將設備分配給客戶", +        "assign-device-to-customer-text": "請選擇要分配給客戶的設備", +        "make-public": "公開", +        "make-private": "私有", +        "no-devices-text": "找不到設備", +        "assign-to-customer-text": "請選擇客戶分配設備", +        "device-details": "設備詳細訊息", +        "add-device-text": "增加新設備", +        "credentials": "憑據", +        "manage-credentials": "管理憑據", +        "delete": "刪除設備", +        "assign-devices": "分配設備", +        "assign-devices-text": "將{count,plural,1 {1 設備} other {# 設備}}分配給客戶", +        "delete-devices": "刪除設備", +        "unassign-from-customer": "取消分配客戶", +        "unassign-devices": "取消分配設備", +        "unassign-devices-action-title": "從客戶處取消分配{count,plural,1 {1 設備} other {# 設備}}", +        "assign-new-device": "分配新設備", + "make-public-device-title": "您確定要將設備 '{{deviceName}}' 設為公開嗎?", +        "make-public-device-text": "確認後,設備及其所有資料將被設為公開並可被其他人存取。", +        "make-private-device-title": "您確定要將設備 '{{deviceName}}' 設為私有嗎?", +        "make-private-device-text": "確認後,設備及其所有資料將被設為私有,不被其他人存取。", +        "view-credentials": "查看憑據", +        "delete-device-title": "您確定要刪除設備的{{deviceName}}嗎?", +        "delete-device-text": "小心!確認後設備及其所有相關資料將無法恢復。", +        "delete-devices-title": "您確定要刪除{count,plural,1 {1 設備} other {# 設備}} 嗎?", +        "delete-devices-action-title": "刪除 {count,plural,1 {1 設備} other {# 設備}}", +        "delete-devices-text": "小心!確認後所有選擇的設備將被刪除,所有相關資料將無法恢復。", +        "unassign-device-title": "您確定要取消分配設備 '{{deviceName}}'?", +        "unassign-device-text": "確認後,設備將被取消分配,客戶將無法存取。", +        "unassign-device": "取消分配設備", +        "unassign-devices-title": "您確定要取消分配{count,plural,1 {1 設備} other {# 設備}} 嗎?", +        "unassign-devices-text": "確認後,所有選擇的設備將被取消分配,並且客戶將無法存取。", +        "device-credentials": "設備憑據", +        "credentials-type": "憑據類型", +        "access-token": "存取令牌", +        "access-token-required": "需要存取令牌", +        "access-token-invalid": "存取令牌長度必須為1到20個字符。", +        "rsa-key": "RSA公鑰", +        "rsa-key-required": "需要RSA公鑰", +        "secret": "密鑰", + "secret-required": "密鑰必填", +        "device-type": "設備類型", +        "device-type-required": "設備類型必填。", +        "select-device-type": "選擇設備類型", +        "enter-device-type": "輸入設備類型", +        "any-device": "任意設備", +        "no-device-types-matching": "沒有找到符合 '{{entitySubtype}}' 的設備類型。", +        "device-type-list-empty": "未選擇設備類型", +        "device-types": "設備類型", +        "name": "名稱", +        "name-required": "名稱必填。", +        "description": "說明", +        "events": "事件", +        "details": "詳細訊息", +        "copyId": "複製設備ID", +        "copyAccessToken": "複製存取令牌", +        "idCopiedMessage": "設備ID已複製到剪貼板", +        "accessTokenCopiedMessage": "設備存取令牌已複製到剪貼板", +        "assignedToCustomer": "分配給客戶", +        "unable-delete-device-alias-title": "無法刪除設備別名", +        "unable-delete-device-alias-text": "設備別名 '{{deviceAlias}}' 不能夠被刪除,因為它被下列部件所使用:
{{widgetsList}}", +        "is-gateway": "是閘道", +        "public": "公開", +        "device-public": "設備公開", +        "select-device": "選擇設備" +    }, + "dialog": { +        "close": "關閉對話框" +    }, +    "error": { +        "unable-to-connect": "無法連接到伺服器!請檢查您的互聯網連接。", +        "unhandled-error-code": "未處理的錯誤代碼: {{errorCode}}", +        "unknown-error": "未知錯誤" +    }, +    "entity": { +        "entity": "實體", +        "entities": "實體", +        "aliases": "實體別名", +        "entity-alias": "實體別名", +        "unable-delete-entity-alias-title": "無法刪除實體別名", +        "unable-delete-entity-alias-text": "實體別名 '{{entityAlias}}' 被以下部件使用不能刪除:
{{widgetsList}}", +        "duplicate-alias-error": "別名 '{{alias}}' 重複。
同一儀表板別名必須唯一。", +        "missing-entity-filter-error": "別名 '{{alias}}' 缺少過濾器", +        "configure-alias": "別名 '{{alias}}' 配置", +        "alias": "別名", +        "alias-required": "實體別名必填。", +        "remove-alias": "移除實體別名", +        "add-alias": "增加實體別名", +        "entity-list": "實體列表", +        "entity-type": "實體類型", +        "entity-types": "實體類型", +        "entity-type-list": "實體類型列表", +        "any-entity": "任意實體", +        "enter-entity-type": "輸入實體類型", +        "no-entities-matching": "沒有找到符合 '{{entity}}' 的實體。", +        "no-entity-types-matching": "沒有找到符合 '{{entityType}}' 類型的實體。", +        "name-starts-with": "名稱開始於", +        "use-entity-name-filter": "用戶過濾", +        "entity-list-empty": "沒有選擇實體。", +        "entity-type-list-empty": "沒有選擇實體類型。", +        "entity-name-filter-required": "實體名過濾器必填。", +        "entity-name-filter-no-entity-matched": "沒有找到以 '{{entity}}' 開頭的實體", +        "all-subtypes": "所有", + "select-entities": "選擇實體", +        "no-aliases-found": "沒有找到別名", +        "no-alias-matching": "沒有找到 '{{alias}}'", +        "create-new-alias": "建立新別名", +        "key": "鍵", +        "key-name": "鍵名", +        "no-keys-found": "沒有找到鍵", +        "no-key-matching": "沒有找到鍵 '{{key}}'", +        "create-new-key": "建立新鍵", +        "type": "類型", +        "type-required": "實體類型必填。", +        "type-device": "設備", +        "type-devices": "設備", +        "list-of-devices": "{ count, plural, 1 {設備} other {# 設備列表} }", +        "device-name-starts-with": "以 '{{prefix}}' 開頭的設備", +        "type-asset": "資產", +        "type-assets": "資產", +        "list-of-assets": "{ count, plural, 1 {資產} other {# 資產列表} }", +        "asset-name-starts-with": "以 '{{prefix}}' 開頭的資產", +        "type-entity-view": "實體視圖", +        "type-entity-views": "實體視圖", +        "list-of-entity-views": "{ count, plural, 1 {實體視圖} other {# 實體視圖列表} }", +        "entity-view-name-starts-with": "以 '{{prefix}}' 開頭的實體視圖", +        "type-rule": "規則", +        "type-rules": "規則", +        "list-of-rules": "{ count, plural, 1 {規則} other {# 規則列表} }", +        "rule-name-starts-with": "以 '{{prefix}}' 開頭的規則", +        "type-plugin": "插件", +        "type-plugins": "插件", +        "list-of-plugins": "{ count, plural, 1 {插件} other {# 插件列表} }", +        "plugin-name-starts-with": "以 '{{prefix}}' 開頭的插件", +        "type-tenant": "租戶", +        "type-tenants": "租戶", +        "list-of-tenants": "{ count, plural, 1 {租戶} other {# 租戶列表} }", +        "tenant-name-starts-with": "以 '{{prefix}}' 開頭的租戶", +        "type-customer": "客戶", +        "type-customers": "客戶", + "list-of-customers": "{ count, plural, 1 {客戶} other {# 客戶列表} }", +        "customer-name-starts-with": "以 '{{prefix}}' 開頭的客戶", +        "type-user": "用戶", +        "type-users": "用戶", +        "list-of-users": "{ count, plural, 1 {用戶} other {# 用戶列表} }", +        "user-name-starts-with": "以 '{{prefix}}' 開頭的用戶", +        "type-dashboard": "儀表板", +        "type-dashboards": "儀表板", +        "list-of-dashboards": "{ count, plural, 1 {儀表板} other {# 儀表板列表} }", +        "dashboard-name-starts-with": "以 '{{prefix}}' 開頭的儀表板", +        "type-alarm": "警告", +        "type-alarms": "警告", +        "list-of-alarms": "{ count, plural, 1 {警告} other {# 警告列表} }", +        "alarm-name-starts-with": "以 '{{prefix}}' 開頭的警告", +        "type-rulechain": "規則鏈", +        "type-rulechains": "規則鏈庫", +        "list-of-rulechains": "{ count, plural, 1 {一個規則鏈} other {# 規則鏈列表} }", +        "rulechain-name-starts-with": "規則鏈前綴名稱 '{{prefix}}'", +        "type-current-customer": "當前客戶", +        "search": "實體檢索", +        "selected-entities": "{ count, plural, 1 {1 實體} other {# 實體} } 被選中", +        "entity-name": "實體名", +        "details": "實體詳細資訊", +        "no-entities-prompt": "沒有找到實體", +        "no-data": "無資料" +    }, + "entity-view": { +        "entity-view": "實體視圖", +        "entity-view-required": "實體視圖必填。", +        "entity-views": "實體視圖", +        "management": "實體視圖管理", +        "view-entity-views": "查看實體視圖", +        "entity-view-alias": "實體視圖別名", +        "aliases": "實體視圖別名", +        "no-alias-matching": "'{{alias}}' 沒有找到。", +        "no-aliases-found": "找不到別名。", +        "no-key-matching": "'{{key}}' 沒有找到。", +        "no-keys-found": "找不到密鑰。", +        "create-new-alias": "建立一個新的!", +        "create-new-key": "建立一個新的!", +        "duplicate-alias-error": "找到重複別名 '{{alias}}'。
實體視圖別名必須是唯一的。", +        "configure-alias": "配置 '{{alias}}' 別名", +        "no-devices-matching": "找不到與 '{{entity}}' 符合的實體視圖。", +        "alias": "別名", +        "alias-required": "需要實體視圖別名。", +        "remove-alias": "刪除實體視圖別名", +        "add-alias": "增加實體視圖別名", +        "name-starts-with": "名稱前綴", +        "entity-view-list": "實體視圖列表", +        "use-entity-view-name-filter": "使用過濾器", +        "entity-view-list-empty": "沒有被選中的實體視圖", +        "entity-view-name-filter-required": "實體視圖名稱過濾器必填。", +        "entity-view-name-filter-no-entity-view-matched": "找不到以'{{entityView}}' 開頭的實體視圖。", +        "add": "增加實體視圖", +        "assign-to-customer": "分配給客戶", +        "assign-entity-view-to-customer": "將實體視圖分配給客戶", +        "assign-entity-view-to-customer-text": "請選擇要分配給客戶的實體視圖", +        "no-entity-views-text": "找不到實體視圖", +        "assign-to-customer-text": "請選擇客戶分配實體視圖", +        "entity-view-details": "實體視圖詳細訊息", +        "add-entity-view-text": "增加新實體視圖", +        "delete": "刪除實體視圖", +        "assign-entity-views": "分配實體視圖", +        "assign-entity-views-text": "分配 { count, plural, 1 {1 實體視圖} other {# 實體視圖} } 給客戶", +        "delete-entity-views": "刪除實體視圖", +        "unassign-from-customer": "取消分配客戶", +        "unassign-entity-views": "取消分配實體視圖", + "unassign-entity-views-action-title": "從客戶處取消分配{count,plural,1 {1 實體視圖} other {# 實體視圖}}", +        "assign-new-entity-view": "分配新實體視圖", +        "delete-entity-view-title": "確定要刪除實體視圖 '{{entityViewName}}'?", +        "delete-entity-view-text": "小心!確認後實體視圖及其所有相關資料將無法恢復。", +        "delete-entity-views-title": "確定要刪除 { count, plural, 1 {1 實體視圖} other {# 實體視圖} }?", +        "delete-entity-views-action-title": "刪除 { count, plural, 1 {1 實體視圖} other {# 實體視圖} }", +        "delete-entity-views-text": "B小心,確認後,所有選擇的實體視圖將被刪除,所有相關的資料將變得無法恢復。", +        "unassign-entity-view-title": "您確定要取消對 '{{entityViewName}}'實體視圖的分配嗎?", +        "unassign-entity-view-text": "確認後,實體視圖將未分配,客戶無法存取。", +        "unassign-entity-view": "未分配實體視圖", +        "unassign-entity-views-title": "您確定要取消分配 { count, plural, 1 {1 實體視圖} other {# 實體視圖} }嗎?", +        "unassign-entity-views-text": "確認後,所有選擇的實體視圖將被分配,客戶無法存取。", +        "entity-view-type": "實體視圖類型", +        "entity-view-type-required": "實體視圖類型必填。", +        "select-entity-view-type": "選擇實體視圖類型", +        "enter-entity-view-type": "輸入實體視圖類型", +        "any-entity-view": "任何實體視圖", +        "no-entity-view-types-matching": "沒有找到符合 '{{entitySubtype}}' 的實體視圖類型。", +        "entity-view-type-list-empty": "實體視圖類型未選擇。", +        "entity-view-types": "實體視圖類型", +        "name": "名稱", +        "name-required": "名稱必填。", +        "description": "描述", +        "events": "事件", +        "details": "詳細資訊", +        "copyId": "複製實體視圖ID", + "assignedToCustomer": "分配給客戶", +        "unable-entity-view-device-alias-title": "無法刪除實體視圖別名", +        "unable-entity-view-device-alias-text": "實體視圖別名 '{{entityViewAlias}}' 不能夠被刪除,因為它被下列部件所使用:
{{widgetsList}}", +        "select-entity-view": "選擇實體視圖", +        "make-public": "實體視圖設為公開", +        "make-private": "實體視圖設為私有", +        "start-date": "開始日期", +        "start-ts": "開始時間", +        "end-date": "結束日期", +        "end-ts": "結束時間", +        "date-limits": "日期限製", +        "client-attributes": "客戶端屬性", +        "shared-attributes": "共享屬性", +        "server-attributes": "服務端屬性", +        "timeseries": "時間序列", +        "client-attributes-placeholder": "客戶端屬性", +        "shared-attributes-placeholder": "共享屬性", +        "server-attributes-placeholder": "服務端屬性", +        "timeseries-placeholder": "時間序列", +        "target-entity": "目標實體", +        "attributes-propagation": "屬性傳播", +        "attributes-propagation-hint": "每次儲存或更新這個實體視圖時,實體視圖將自動從目標實體複製指定的屬性。由於性能原因,目標實體屬性不會在每次屬性更改時傳播到實體視圖。您可以通過配置\"copy to view\"規則鏈中的規則節點,並將\"Post attributes\"和\"attributes Updated\"消息連結到新規則節點,從而啟用自動傳播。", +        "timeseries-data": "時間序列資料", +        "timeseries-data-hint": "配置目標實體的時間序列資料鍵,以便實體視圖可以存取這些鍵。這個時間序列資料是只讀的。", +        "make-public-entity-view-title": "你確定你想建立公開 '{{entityViewName}}' 實體視圖?", +        "make-public-entity-view-text": "確認後,實體視圖 及其所有資料將被公開並被他人存取。", +        "make-private-entity-view-title": "你確定你想建立私有 '{{entityViewName}}' 實體視圖?", +        "make-private-entity-view-text": "確認後,實體視圖及其所有資料將被私有化,無法被他人存取。" + }, + "event": { +        "event-type": "事件類型", +        "type-error": "錯誤", +        "type-lc-event": "生命週期事件", +        "type-stats": "類型統計", +        "type-debug-rule-node": "測試", +        "type-debug-rule-chain": "測試", +        "no-events-prompt": "找不到事件", +        "error": "錯誤", +        "alarm": "報警", +        "event-time": "事件時間", +        "server": "伺服器", +        "body": "整體", +        "method": "方法", +        "type": "類型", +        "entity": "實體", +        "message-id": "消息ID", +        "message-type": "消息類型", +        "data-type": "資料類型", +        "relation-type": "關係類型", +        "metadata": "元資料", +        "data": "資料", +        "event": "事件", +        "status": "狀態", +        "success": "成功", +        "failed": "失敗", +        "messages-processed": "消息處理", +        "errors-occurred": "錯誤發生" +    }, + "extension": { +        "extensions": "擴展", +        "selected-extensions": "{ count, plural, 1 {1 擴展} other {# 擴展} } 被選擇", +        "type": "類型", +        "key": "鍵名", +        "value": "值", +        "id": "ID", +        "extension-id": "擴展ID", +        "extension-type": "擴展類型", +        "transformer-json": "JSON *", +        "unique-id-required": "當前擴展ID已經存在。", +        "delete": "刪除擴展", +        "add": "增加擴展", +        "edit": "編輯擴展", +        "delete-extension-title": "確實要刪除擴展名'{{extensionId}}'嗎?", +        "delete-extension-text": "小心,確認後,擴展和所有相關資料將變得無法恢復。", +        "delete-extensions-title": "您確定要刪除 { count, plural, 1 {1 表達式} other {# 表達式} }嗎?", +        "delete-extensions-text": "小心,確認後,所有選擇的擴展將被刪除。", +        "converters": "轉換器", +        "converter-id": "轉換器序號", +        "configuration": "配置", +        "converter-configurations": "轉換器的配置", +        "token": "安全令牌", +        "add-converter": "增加轉換器", +        "add-config": "增加轉換器配置", +        "device-name-expression": "設備名稱表達式", +        "device-type-expression": "設備類型表達式", +        "custom": "顧客", +        "to-double": "加倍", +        "transformer": "轉換器", +        "json-required": "轉換器JSON必填。", +        "json-parse": "無法解析轉換器JSON。", +        "attributes": "屬性", +        "add-attribute": "增加屬性", +        "add-map": "增加映射元素", +        "timeseries": "時間序列", +        "add-timeseries": "增加時間序列", +        "field-required": "必填字段", +        "brokers": "代理伺服器組", +        "add-broker": "增加代理伺服器", +        "host": "主機", +        "port": "連接埠", +        "port-range": "連接埠應該在1到65535的範圍內。", +        "ssl": "Ssl", +        "credentials": "證書", +        "username": "用戶名", +        "password": "密碼", +        "retry-interval": "以毫秒為單位的重試間隔", +        "anonymous": "匿名", +        "basic": "Basic", +        "pem": "PEM", + "ca-cert": "CA證書文件 *", +        "private-key": "私鑰文件 *", +        "cert": "證書文件 *", +        "no-file": "沒有選擇文件。", +        "drop-file": "刪除文件或單擊以選擇要上載的文件。", +        "mapping": "映射", +        "topic-filter": "主題濾波", +        "converter-type": "轉換類型", +        "converter-json": "Json", +        "json-name-expression": "設備名稱JSON表達式", +        "topic-name-expression": "設備名稱主題表達式", +        "json-type-expression": "設備類型JSON表達式", +        "topic-type-expression": "設備類型主題表達式", +        "attribute-key-expression": "屬性關鍵字表達式", +        "attr-json-key-expression": "屬性鍵JSON表達式", +        "attr-topic-key-expression": "屬性關鍵字主題表達式", +        "request-id-expression": "請求ID表達式", +        "request-id-json-expression": "請求ID JSON表達式", +        "request-id-topic-expression": "請求ID主題表達式", +        "response-topic-expression": "響應主題表達式", +        "value-expression": "值表達式", +        "topic": "主題", +        "timeout": "毫秒超時", +        "converter-json-required": "轉換JSON是必需的。", +        "converter-json-parse": "無法解析轉換JSON。", +        "filter-expression": "過濾表達式", +        "connect-requests": "連接請求", +        "add-connect-request": "增加連接請求", +        "disconnect-requests": "斷開請求", +        "add-disconnect-request": "增加斷開請求", +        "attribute-requests": "屬性請求", +        "add-attribute-request": "增加屬性請求", +        "attribute-updates": "屬性更新", +        "add-attribute-update": "增加屬性更新", +        "server-side-rpc": "服務端RPC", +        "add-server-side-rpc-request": "增加服務端RPC請求", +        "device-name-filter": "設備名稱濾波", +        "attribute-filter": "屬性濾波", +        "method-filter": "方法濾波", +        "request-topic-expression": "請求主題表達式", +        "response-timeout": "毫秒內響應超時", +        "topic-expression": "主題表達", +        "client-scope": "客戶範圍", +        "add-device": "增加伺服器", +        "opc-server": "伺服器組", +        "opc-add-server": "增加伺服器", +        "opc-add-server-prompt": "請增加伺服器", +        "opc-application-name": "應用名稱", +        "opc-application-uri": "應用URI", +        "opc-scan-period-in-seconds": "秒級掃描週期", +        "opc-security": "安全性", +        "opc-identity": "身份", +        "opc-keystore": "密鑰庫", +        "opc-type": "類型", +        "opc-keystore-type": "類型", +        "opc-keystore-location": "位置 *", +        "opc-keystore-password": "密碼", +        "opc-keystore-alias": "別名", +        "opc-keystore-key-password": "密鑰密碼", +        "opc-device-node-pattern": "設備節點模式", +        "opc-device-name-pattern": "設備名稱模式", +        "modbus-server": "Servers/slaves", +        "modbus-add-server": "增加 server/slave", +        "modbus-add-server-prompt": "請增加 server/slave", +        "modbus-transport": "傳輸", +        "modbus-port-name": "串口名稱", +        "modbus-encoding": "編碼", +        "modbus-parity": "奇偶性", +        "modbus-baudrate": "鮑率", +        "modbus-databits": "資料位", +        "modbus-stopbits": "停止位", + "modbus-databits-range": "資料位應該在7到8的範圍內。", +        "modbus-stopbits-range": "停止位應該在1到2的範圍內。", +        "modbus-unit-id": "單位編號", +        "modbus-unit-id-range": "單位ID應該在1到247的範圍內", +        "modbus-device-name": "設備名稱", +        "modbus-poll-period": "輪詢週期 (ms)", +        "modbus-attributes-poll-period": "輪詢屬性週期 (ms)", +        "modbus-timeseries-poll-period": "時間序列輪詢週期 (ms)", +        "modbus-poll-period-range": "輪詢週期應為正值。", +        "modbus-tag": "標籤", +        "modbus-function": "函數", +        "modbus-register-address": "寄存器地址", +        "modbus-register-address-range": "寄存器地址應該在0到65535的範圍內。", +        "modbus-register-bit-index": "位索引", +        "modbus-register-bit-index-range": "位索引應該在0到15的範圍內。", +        "modbus-register-count": "寄存器計數", +        "modbus-register-count-range": "寄存器計數應該是一個正值。", +        "modbus-byte-order": "字節順序", +        "sync": { +            "status": "狀態", +            "sync": "同步", +            "not-sync": "不同步", +            "last-sync-time": "最後同步時間", +            "not-available": "無法使用" +        }, +        "export-extensions-configuration": "匯出擴展配置", +        "import-extensions-configuration": "匯入擴展配置", +        "import-extensions": "匯入擴展", +        "import-extension": "匯入擴展", +        "export-extension": "匯出擴展", +        "file": "擴展文件", +        "invalid-file-error": "無效的擴展文件" + }, + "fullscreen": { +        "expand": "展開到全螢幕", +        "exit": "退出全螢幕", +        "toggle": "切換全螢幕模式", +        "fullscreen": "全螢幕" +    }, +    "function": { +        "function": "函數" +    }, +    "grid": { +        "delete-item-title": "您確定要刪除此項嗎?", +        "delete-item-text": "注意,確認後此項及其所有相關資料將變得無法恢復。", +        "delete-items-title": "你確定你要刪除 { count, plural, 1 {1 項} other {# 項} }嗎?", +        "delete-items-action-title": "刪除 { count, plural, 1 {1 項} other {# 項} }", +        "delete-items-text": "注意,確認後所有選擇的項目將被刪除,所有相關資料將無法恢復。", +        "add-item-text": "增加新項目", +        "no-items-text": "沒有找到項目", +        "item-details": "項目詳細訊息", +        "delete-item": "刪除項目", +        "delete-items": "刪除項目", +        "scroll-to-top": "滾動到頂部" +    }, +    "help": { +        "goto-help-page": "轉到幫助頁面" +    }, +    "home": { +        "home": "首頁", +        "profile": "屬性", +        "logout": "註銷", +        "menu": "菜單", +        "avatar": "頭像", +        "open-user-menu": "打開用戶菜單" +    }, +    "import": { +        "no-file": "沒有選擇文件", +        "drop-file": "拖動一個JSON文件或者單擊以選擇要上傳的文件。" +    }, +    "item": { +        "selected": "選擇" +    }, +    "js-func": { +        "no-return-error": "函數必須返回值!", +        "return-type-mismatch": "函數必須返回 '{{type}}' 類型的值!", +        "tidy": "整理" +    }, + "key-val": { +        "key": "鍵名", +        "value": "值", +        "remove-entry": "刪除條目", +        "add-entry": "增加條目", +        "no-data": "沒有條目" +    }, +    "layout": { +        "layout": "佈局", +        "manage": "佈局管理", +        "settings": "佈局設定", +        "color": "顏色", +        "main": "主體", +        "right": "右側", +        "select": "選擇目標佈局" +    }, +    "legend": { +        "position": "圖例位置", +        "show-max": "顯示最大值", +        "show-min": "顯示最小值", +        "show-avg": "顯示平均值", +        "show-total": "顯示總數", +        "settings": "圖例設定", +        "min": "最小值", +        "max": "最大值", +        "avg": "平均值", +        "total": "總數" +    }, +    "login": { +        "login": "登入", +        "request-password-reset": "請求密碼重置", +        "reset-password": "重置密碼", +        "create-password": "建立密碼", +        "passwords-mismatch-error": "輸入的密碼必須相同!", +        "password-again": "再次輸入密碼", +        "sign-in": "登入 ", +        "username": "用戶名(電子郵件)", +        "remember-me": "記住我", +        "forgot-password": "忘記密碼?", +        "password-reset": "密碼重置", +        "new-password": "新密碼", +        "new-password-again": "再次輸入新密碼", +        "password-link-sent-message": "密碼重置連結已成功發送!", +        "email": "電子郵件" +    }, + "position": { +        "top": "頂部", +        "bottom": "底部", +        "left": "左側", +        "right": "右側" +    }, +    "profile": { +        "profile": "屬性", +        "change-password": "更改密碼", +        "current-password": "當前密碼" +    }, +    "relation": { +        "relations": "關聯", +        "direction": "方向", +        "search-direction": { +            "FROM": "從", +            "TO": "到" +        }, +        "direction-type": { +            "FROM": "從", +            "TO": "到" +        }, +        "from-relations": "向外的關聯", +        "to-relations": "向內的關聯", +        "selected-relations": "{ count, plural, 1 {1 關聯} other {# 關聯} } 被選中", +        "type": "類型", +        "to-entity-type": "到實體類型", +        "to-entity-name": "到實體名稱", +        "from-entity-type": "從實體類型", +        "from-entity-name": "從實體類型", +        "to-entity": "到實體", +        "from-entity": "從實體", +        "delete": "刪除關聯", +        "relation-type": "關聯類型", +        "relation-type-required": "關聯類型必填", +        "any-relation-type": "任意類型", +        "add": "增加關聯", +        "edit": "編輯關聯", +        "delete-to-relation-title": "確定要刪除實體 '{{entityName}}' 的關聯嗎?", +        "delete-to-relation-text": "確定刪除後實體 '{{entityName}}' 將取消與當前實體的關聯關係。", +        "delete-to-relations-title": "確定要刪除 { count, plural, 1 {1 關聯} other {# 關聯} }?", +        "delete-to-relations-text": "確定刪除所有選擇的關聯關係後,與當前實體對應的所有關聯關係將被移除。", +        "delete-from-relation-title": "確定要從實體 '{{entityName}}' 刪除關聯嗎?", +        "delete-from-relation-text": "確定刪除後,當前實體將與實體 '{{entityName}}' 取消關聯", +        "delete-from-relations-title": "確定刪除 { count, plural, 1 {1 關聯} other {# 關聯} } 嗎?", +        "delete-from-relations-text": "確定刪除所有選擇的關聯關係後,當前實體將與對應的實體取消關聯", +        "remove-relation-filter": "移除關聯過濾器", +        "add-relation-filter": "增加關聯過濾器", +        "any-relation": "任意關聯", +        "relation-filters": "關聯過濾器", +        "additional-info": "附加訊息 (JSON)", +        "invalid-additional-info": "無法解析附加訊息json。" +    }, + "rulechain": { +        "rulechain": "規則鏈", +        "rulechains": "規則鏈庫", +        "root": "根實體", +        "delete": "刪除規則", +        "activate": "啟動規則", +        "suspend": "暫停規則", +        "active": "啟動", +        "suspended": "暫停", +        "name": "名稱", +        "name-required": "名稱必填。", +        "description": "描述", +        "add": "增加規則", +        "set-root": "建立規則鏈根", +        "set-root-rulechain-title": "您確定要生成規則鏈'{{RuleChainName}}'根嗎?", +        "set-root-rulechain-text": "確認之後,規則鏈將變為根規格鏈,並將處理所有傳入的傳輸消息。", +        "delete-rulechain-title": " 確實要刪除規則鏈'{{ruleChainName}}'嗎?", +        "delete-rulechain-text": "小心,在確認規則鏈和所有相關資料將變得無法恢復。", +        "delete-rulechains-title": "確實要刪除{count, plural, 1 { 1 規則鏈}其他{# 規則鏈庫}}嗎?", +        "delete-rulechains-action-title": "刪除 { count, plural, 1 {1 規則鏈} other {# 規則鏈庫} }", +        "delete-rulechains-text": "小心,確認後,所有選擇的規則鏈將被刪除,所有相關的資料將變得無法恢復。", +        "add-rulechain-text": "增加新的規則鏈", +        "no-rulechains-text": "規則鏈沒有發現", +        "rulechain-details": "規則鏈詳細資訊", +        "details": "詳細資訊", +        "events": "事件", +        "system": "系統", +        "import": "匯入規則", +        "export": "匯出規則", +        "export-failed-error": "無法匯出規則:{{error}}", +        "create-new-rulechain": "建立新的規則鏈", +        "rulechain-file": "規則鏈文件", +        "invalid-rulechain-file-error": "不能匯入規則鏈:無效的規則鏈資料格式。", +        "copyId": "複製規則鏈ID", +        "idCopiedMessage": "規則ID已經複製到剪貼板", +        "select-rulechain": "選擇規則鏈", +        "no-rulechains-matching": "沒有發現符合'{{entity}}'的規則鏈。", +        "rulechain-required": "規則鏈必填", +        "management": "規則集管理", +        "debug-mode": "測試模式" +    }, + "rulenode": { +        "details": "詳細資訊", +        "events": "事件", +        "search": "搜尋節點", +        "open-node-library": "打開節點庫", +        "add": "增加規則節點", +        "name": "名稱", +        "name-required": "名稱必填。", +        "type": "類型", +        "description": "描述", +        "delete": "刪除規則節點", +        "select-all-objects": "選擇所有節點和連接", +        "deselect-all-objects": "取消選擇所有節點和連接", +        "delete-selected-objects": "刪除選擇的節點和連接", +        "delete-selected": "刪除選擇", +        "select-all": "選擇全部", +        "copy-selected": "選擇副本", +        "deselect-all": "取消選擇", +        "rulenode-details": "規則節點詳細資訊", +        "debug-mode": "測試模式", +        "configuration": "配置", +        "link": "連結", +        "link-details": "規則節點連結詳細資訊", +        "add-link": "增加連結", +        "link-label": "連結標籤", +        "link-label-required": "連結標籤必填", +        "custom-link-label": "自定義連結標籤", +        "custom-link-label-required": "自定義連結標籤必填", +        "type-filter": "濾波器", +        "type-filter-details": "使用配置條件過濾傳入消息", +        "type-enrichment": "屬性集", +        "type-enrichment-details": "向消息元資料中增加附加訊息", +        "type-transformation": "變換", +        "type-transformation-details": "更改消息有效載荷和元資料", +        "type-action": "動作", +        "type-action-details": "執行特別動作", +        "type-external": "外部的", +        "type-external-details": "與外部系統交互", +        "type-rule-chain": "規則鏈", +        "type-rule-chain-details": "將傳入消息轉發到指定的規則鏈", +        "type-in​​put": "輸入", +        "type-in​​put-details": "規則鏈的邏輯輸入,將傳入消息轉發到下一個相關規則節點", +        "directive-is-not-loaded": "定義的配置指令 '{{directiveName}}' 不可用。", +        "ui-resources-load-error": "加載配置UI資源失敗。", +        "invalid-target-rulechain": "無法解析目標規則鏈!", +        "test-script-function": "測試腳本功能", +        "message": "消息", +        "message-type": "消息類型", +        "message-type-required": "消息類型必填", +        "metadata": "元資料", +        "metadata-required": "元資料項不能為空。", +        "output": "輸出", +        "test": "測試", +        "help": "幫助" +    }, +    "tenant": { +        "tenant": "租戶", +        "tenants": "租戶", +        "management": "租戶管理", +        "add": "增加租戶", +        "admins": "管理員", +        "manage-tenant-admins": "管理租戶管理員", +        "delete": "刪除租戶", +        "add-tenant-text": "增加新租戶", +        "no-tenants-text": "沒有找到租戶", +        "tenant-details": "租客詳細資訊", +        "delete-tenant-title": "您確定要刪除租戶'{{tenantTitle}}'嗎?", +        "delete-tenant-text": "小心!確認後,租戶和所有相關資料將無法恢復。", +        "delete-tenants-title": "您確定要刪除 {count,plural,1 {1 租戶} other {# 租戶}} 嗎?", +        "delete-tenants-action-title": "刪除 { count, plural, 1 {1 租戶} other {# 租戶} }", +        "delete-tenants-text": "小心!確認後,所有選擇的租戶將被刪除,所有相關資料將無法恢復。", +        "title": "標題", +        "title-required": "標題必填。", +        "description": "描述", +        "details": "詳細資訊", +        "events": "事件", +        "copyId": "複製租戶ID", +        "idCopiedMessage": "租戶ID已經複製到剪貼板", +        "select-tenant": "選擇租戶", +        "no-tenants-matching": "沒有找到符合 '{{entity}}' 的租戶", +        "tenant-required": "租戶必填" +    }, +    "timeinterval": { +        "seconds-interval": "{ seconds, plural, 1 {1 秒} other {# 秒} }", +        "minutes-interval": "{ minutes, plural, 1 {1 分} other {# 分} }", +        "hours-interval": "{ hours, plural, 1 {1 小時} other {# 小時} }", +        "days-interval": "{ days, plural, 1 {1 天} other {# 天} }", +        "days": "天", +        "hours": "時", +        "minutes": "分", +        "seconds": "秒", +        "advanced": "高級" +    }, + "timewindow": { +        "days": "{ days, plural, 1 { 天 } other {# 天 } }", +        "hours": "{ hours, plural, 0 { 小時 } 1 {1 小時 } other {# 小時 } }", +        "minutes": "{ minutes, plural, 0 { 分 } 1 {1 分 } other {# 分 } }", +        "seconds": "{ seconds, plural, 0 { 秒 } 1 {1 秒 } other {# 秒 } }", +        "realtime": "實時", +        "history": "歷史", +        "last-prefix": "最後", +        "period": "從 {{ startTime }} 到 {{ endTime }}", +        "edit": "編輯時間窗口", +        "date-range": "日期範圍", +        "last": "最後", +        "time-period": "時間段" +    }, +    "user": { +        "user": "用戶", +        "users": "用戶", +        "customer-users": "客戶用戶", +        "tenant-admins": "租戶管理員", +        "sys-admin": "系統管理員", +        "tenant-admin": "租戶管理員", +        "customer": "客戶", +        "anonymous": "匿名", +        "add": "增加用戶", +        "delete": "刪除用戶", +        "add-user-text": "增加新用戶", +        "no-users-text": "找不到用戶", +        "user-details": "用戶詳細訊息", +        "delete-user-title": "您確定要刪除用戶 '{{userEmail}}' 嗎?", +        "delete-user-text": "小心!確認後,用戶和所有相關資料將無法恢復。", +        "delete-users-title": "你確定你要刪除 { count, plural, 1 {1 用戶} other {# 用戶} } 嗎?", +        "delete-users-action-title": "刪除 { count, plural, 1 {1 用戶} other {# 用戶} }", +        "delete-users-text": "小心!確認後,所有選擇的用戶將被刪除,所有相關資料將無法恢復。", +        "activation-email-sent-message": "啟動電子郵件已成功發送!", +        "resend-activation": "重新發送啟動", +        "email": "電子郵件", +        "email-required": "電子郵件必填。", +        "invalid-email-format": "無效的郵件格式。", +        "first-name": "名字", +        "last-name": "姓", +        "description": "描述", +        "default-dashboard": "預設面板", +        "always-fullscreen": "始終全螢幕", +        "select-user": "選擇用戶", +        "no-users-matching": "沒有找到符合 '{{entity}}' 的用戶。", +        "user-required": "用戶必填", +        "activation-method": "啟動方式", +        "display-activation-link": "顯示啟動連結", +        "send-activation-mail": "發送啟動郵件", +        "activation-link": "用戶啟動連結", +        "activation-link-text": "使用該連結 啟動 啟動用戶:", +        "copy-activation-link": "複製用戶啟動連結", +        "activation-link-copied-message": "用戶啟動連結已經複製到剪貼板", +        "details": "詳細訊息" +    }, +    "value": { +        "type": "值類型", +        "string": "字符串", +        "string-value": "字符串值", +        "integer": "數字", +        "integer-value": "數字值", +        "invalid-integer-value": "整數值無效", +        "double": "雙精度浮點數", +        "double-value": "雙精度浮點數值", +        "boolean": "布林", +        "boolean-value": "布林值", +        "false": "假", +        "true": "真", +        "long": "Long" +    }, +    "widget": { +        "widget-library": "部件庫", +        "widget-bundle": "部件包", +        "select-widgets-bundle": "選擇部件包", +        "management": "管理部件", +        "editor": "部件編輯器", +        "widget-type-not-found": "加載部件配置出錯。
可能關聯的\n 部件已經刪除了。", +        "widget-type-load-error": "由於以下錯誤未加載小部件:", +        "remove": "刪除部件", +        "edit": "編輯部件", +        "remove-widget-title": "確實要刪除 '{{widgetTitle}}'部件嗎?", +        "remove-widget-text": "確認後,控件和所有相關資料將變得無法恢復。", +        "timeseries": "時間序列", +        "search-data": "搜尋資料", +        "no-data-found": "沒有找到資料", +        "latest-values": "最新值", +        "rpc": "控件部件", +        "alarm": "警告部件", +        "static": "靜態部件", +        "select-widget-type": "選擇窗口部件類型", +        "missing-widget-title-error": "部件標題必須指定!", +        "widget-saved": "部件已儲存", +        "unable-to-save-widget-error": "無法儲存部件!控件有錯誤!", +        "save": "儲存部件", +        "saveAs": "部件另存為", +        "save-widget-type-as": "部件類型另存為", +        "save-widget-type-as-text": "請輸入新的部件標題或選擇目標部件包", +        "toggle-fullscreen": "切換全螢幕", +        "run": "執行部件", +        "title": "部件標題", +        "title-required": "需要部件標題。", +        "type": "部件類型", +        "resources": "資源", +        "resource-url": "JavaScript/CSS URL", +        "remove-resource": "刪除資源", +        "add-resource": "增加資源", +        "html": "HTML", +        "tidy": "整理", +        "css": "CSS", +        "settings-schema": "設定模式", +        "datakey-settings-schema": "資料鍵設定模式", +        "javascript": "Javascript", +        "remove-widget-type-title": "您確定要刪除部件類型 '{{widgetName}}'嗎?", +        "remove-widget-type-text": "確認後,窗口部件類型和所有相關資料將無法恢復。", +        "remove-widget-type": "刪除部件類型", +        "add-widget-type": "增加新的部件類型", +        "widget-type-load-failed-error": "無法加載部件類型!", +        "widget-template-load-failed-error": "無法加載部件模板!", +        "add": "增加部件", +        "undo": "復原部件更改", +        "export": "匯出部件" +    }, + "widget-action": { +        "header-button": "部件頂部按鈕", +        "open-dashboard-state": "切換到新儀表板狀態", +        "update-dashboard-state": "更新當前儀表板狀態", +        "open-dashboard": "切換到另一個儀表板", +        "custom": "自定義動作", +        "target-dashboard-state": "目標儀表板狀態", +        "target-dashboard-state-required": "目標儀表板狀態必填", +        "set-entity-from-widget": "從部件中設定實體", +        "target-dashboard": "目標儀表板", +        "open-right-layout": "打開右側佈局 (移動端視圖)" +    }, +    "widgets-bundle": { +        "current": "當前包", +        "widgets-bundles": "部件包", +        "add": "增加部件包", +        "delete": "刪除部件包", +        "title": "標題", +        "title-required": "標題必填。", +        "add-widgets-bundle-text": "增加新的部件包", +        "no-widgets-bundles-text": "找不到部件包", +        "empty": "部件包是空的", +        "details": "詳細資訊", +        "widgets-bundle-details": "部件包詳細訊息", +        "delete-widgets-bundle-title": "您確定要刪除部件包 '{{widgetsBundleTitle}}'嗎?", +        "delete-widgets-bundle-text": "小心!確認後,部件包和所有相關資料將無法恢復。", +        "delete-widgets-bundles-title": "你確定你要刪除 { count, plural, 1 {1 部件包} other {# 部件包} } 嗎?", +        "delete-widgets-bundles-action-title": "刪除 { count, plural, 1 {1 部件包} other {# 部件包} }", +        "delete-widgets-bundles-text": "小心!確認後,所有選擇的部件包將被刪除,所有相關資料將無法恢復。", +        "no-widgets-bundles-matching": "沒有找到與 '{{widgetsBundle}}' 符合的部件包。", +        "widgets-bundle-required": "需要部件包。", +        "system": "系統", +        "import": "匯入部件包", +        "export": "匯出部件包", +        "export-failed-error": "無法匯出部件包: {{error}}", +        "create-new-widgets-bundle": "建立新的部件包", +        "widgets-bundle-file": "部件包文件", +        "invalid-widgets-bundle-file-error": "無法匯入部件包:無效的部件包資料結構。" +    }, +    "widget-config": { +        "data": "資料", +        "settings": "設定", +        "advanced": "高級", +        "title": "標題", +        "general-settings": "一般設定", +        "display-title": "顯示標題", +        "drop-shadow": "陰影", +        "enable-fullscreen": "啟用全螢幕", +        "background-color": "背景顏色", +        "text-color": "文字顏色", +        "padding": "填充", +        "margin": "邊緣", +        "widget-style": "部件風格", +        "title-style": "標題風格", +        "mobile-mode-settings": "移動端設定", +        "order": "順序", +        "height": "高度", +        "units": "特殊符號展示值", +        "decimals": "浮點數後的位數", +        "timewindow": "時間窗口", +        "use-dashboard-timewindow": "使用儀表板的時間窗口", +        "display-legend": "顯示圖例", +        "datasources": "資料源", +        "maximum-datasources": "最大允許 { count, plural, 1 {1 資料} other {# 資料} }", +        "datasource-type": "類型", +        "datasource-parameters": "參數", +        "remove-datasource": "移除資料源", +        "add-datasource": "增加資料源", +        "target-device": "目標設備", +        "alarm-source": "警告源", +        "actions": "動作", +        "action": "動作", +        "add-action": "增加動作", +        "search-actions": "動作檢索", +        "action-source": "動作源", +        "action-source-required": "動作源必填", +        "action-name": "動作名稱", +        "action-name-required": "動作名稱必填。", +        "action-name-not-unique": "動作名稱已經存在。
統一動作源的動作名稱必須唯一。", +        "action-icon": "圖示", +        "action-type": "類型", +        "action-type-required": "類型必填", +        "edit-action": "編輯動作", +        "delete-action": "刪除動作", +        "delete-action-title": "刪除部件動作", +        "delete-action-text": "確定要刪除部件動作 '{{actionName}}' 嗎?" +    }, +    "widget-type": { +        "import": "匯入部件類型", +        "export": "匯出部件類型", +        "export-failed-error": "無法匯出部件類型: {{error}}", +        "create-new-widget-type": "建立新的部件類型", +        "widget-type-file": "部件類型文件", +        "invalid-widget-type-file-error": "無法匯入部件類型:無效的部件類型資料結構。" +    }, + "widgets": { +        "date-range-navigator": { +            "localizationMap": { +                "Sun": "週日", +                "Mon": "週一", +                "Tue": "週二", +                "Wed": "週三", +                "Thu": "週四", +                "Fri": "週五", +                "Sat": "週六", +                "Jan": "1月", +                "Feb": "2月", +                "Mar": "3月", +                "Apr": "4月", +                "May": "5月", +                "Jun": "6月", +                "Jul": "7月", +                "Aug": "8月", +                "Sep": "9月", +                "Oct": "10月", +                "Nov": "11月", +                "Dec": "12月", +                "January": "一月", +                "February": "二月", +                "March": "三月", +                "April": "四月", +                "June": "六月", +                "July": "七月", +                "August": "八月", +                "September": "九月", +                "October": "十月", +                "November": "十一月", +                "December": "十二月", +                "Custom Date Range": "自定義日期範圍", +                "Date Range Template": "日期範圍模板", +                "Today": "今天", +                "Yesterday": "昨天", +                "This Week": "本星期", +                "Last Week": "上個星期", +                "This Month": "這個月", +                "Last Month": "上個月", +                "Year": "年", +                "This Year": "今年", +                "Last Year": "去年", +                "Date picker": "日期選擇器", +                "Hour": "小時", +                "Day": "天", +                "Week": "週", +                "2 weeks": "2週", +                "Month": "月", +                "3 months": "3個月", +                "6 months": "6個月", +                "Custom interval": "自定義間隔", +                "Interval": "間隔", +                "Step size": "步長", +                "Ok": "Ok" +            } +        } +    }, +    "icon": { +        "icon": "圖示", +        "select-icon": "選擇圖示", +        "material-icons": "素材圖示", +        "show-all": "顯示所有圖示" +    }, +    "custom": { +        "widget-action": { +            "action-cell-button": "動作單元格按鈕", +            "row-click": "點選行", +            "marker-click": "點選標記", +            "polygon-click": "單擊多邊形", +            "tooltip-tag-action": "提示標籤動作" +        } +    }, +    "language": { +        "language": "語言", +        "locales": { +            "de_DE": "德文", +            "en_US": "英文", +            "fr_FR": "法文", +            "ko_KR": "韓文", +            "zh_CN": "簡體中文", +            "zh_TW": "繁體中文", +            "ru_RU": "俄文", +            "es_ES": "西班牙文", +            "it_IT": "意大利文", +            "ja_JA": "日文", +            "tr_TR": "土耳其文", +            "fa_IR": "波斯文", +            "uk_UA": "烏克蘭文", +            "cs_CZ": "捷克文" +        } +    } +} From 3ba310dff0b15ef5fde824f7a7fd82ed51014801 Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Mon, 6 Jan 2020 16:39:51 +0200 Subject: [PATCH 41/46] Fix didn't disable timewindow button (#2312) * Add support import label * Fix didn't disable timewindow button --- ui/src/app/components/timewindow.directive.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ui/src/app/components/timewindow.directive.js b/ui/src/app/components/timewindow.directive.js index 991a3838ff..db028535a0 100644 --- a/ui/src/app/components/timewindow.directive.js +++ b/ui/src/app/components/timewindow.directive.js @@ -212,7 +212,7 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM } } - scope.isTimewindowDisabled = function () { + function isTimewindowDisabled () { return scope.disabled || (!scope.isEdit && scope.model.hideInterval && scope.model.hideAggregation && scope.model.hideAggInterval); } @@ -247,10 +247,16 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM model.hideAggregation = value.hideAggregation; model.hideAggInterval = value.hideAggInterval; } - scope.timewindowDisabled = scope.isTimewindowDisabled(); + scope.timewindowDisabled = isTimewindowDisabled(); scope.updateDisplayValue(); }; + scope.$watchGroup(['disabled', 'isEdit'], function(newValue, oldValue) { + if (!angular.equals(newValue, oldValue)) { + scope.timewindowDisabled = isTimewindowDisabled(); + } + }); + $compile(element.contents())(scope); } From 9b42397c4a820688daf07117cb7efefa3f387f46 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 6 Jan 2020 16:41:04 +0200 Subject: [PATCH 42/46] Update License header year to 2020 --- application/build.gradle | 2 +- application/pom.xml | 2 +- application/src/main/assembly/windows.xml | 2 +- application/src/main/conf/logback.xml | 2 +- application/src/main/conf/thingsboard.conf | 2 +- application/src/main/data/upgrade/1.3.0/schema_update.cql | 2 +- application/src/main/data/upgrade/1.3.1/schema_update.sql | 2 +- application/src/main/data/upgrade/1.4.0/schema_update.cql | 2 +- application/src/main/data/upgrade/1.4.0/schema_update.sql | 2 +- application/src/main/data/upgrade/2.0.0/schema_update.cql | 2 +- application/src/main/data/upgrade/2.0.0/schema_update.sql | 2 +- application/src/main/data/upgrade/2.1.1/schema_update.cql | 2 +- application/src/main/data/upgrade/2.1.1/schema_update.sql | 2 +- application/src/main/data/upgrade/2.1.2/schema_update.cql | 2 +- application/src/main/data/upgrade/2.1.2/schema_update.sql | 2 +- application/src/main/data/upgrade/2.2.0/schema_update.sql | 2 +- application/src/main/data/upgrade/2.3.1/schema_update.sql | 2 +- application/src/main/data/upgrade/2.4.0/schema_update.sql | 2 +- application/src/main/data/upgrade/2.4.2/schema_update.sql | 2 +- .../org/thingsboard/server/ThingsboardInstallApplication.java | 2 +- .../org/thingsboard/server/ThingsboardServerApplication.java | 2 +- .../java/org/thingsboard/server/actors/ActorSystemContext.java | 2 +- .../main/java/org/thingsboard/server/actors/app/AppActor.java | 2 +- .../java/org/thingsboard/server/actors/app/AppInitMsg.java | 2 +- .../java/org/thingsboard/server/actors/device/DeviceActor.java | 2 +- .../thingsboard/server/actors/device/DeviceActorCreator.java | 2 +- .../server/actors/device/DeviceActorMessageProcessor.java | 2 +- .../server/actors/device/DeviceActorToRuleEngineMsg.java | 2 +- .../java/org/thingsboard/server/actors/device/SessionInfo.java | 2 +- .../thingsboard/server/actors/device/SessionInfoMetaData.java | 2 +- .../server/actors/device/SessionTimeoutCheckMsg.java | 2 +- .../server/actors/device/ToDeviceRpcRequestMetadata.java | 2 +- .../server/actors/device/ToServerRpcRequestMetadata.java | 2 +- .../thingsboard/server/actors/rpc/BasicRpcSessionListener.java | 2 +- .../org/thingsboard/server/actors/rpc/RpcBroadcastMsg.java | 2 +- .../org/thingsboard/server/actors/rpc/RpcManagerActor.java | 2 +- .../org/thingsboard/server/actors/rpc/RpcSessionActor.java | 2 +- .../org/thingsboard/server/actors/rpc/RpcSessionClosedMsg.java | 2 +- .../thingsboard/server/actors/rpc/RpcSessionConnectedMsg.java | 2 +- .../server/actors/rpc/RpcSessionCreateRequestMsg.java | 2 +- .../server/actors/rpc/RpcSessionDisconnectedMsg.java | 2 +- .../org/thingsboard/server/actors/rpc/RpcSessionTellMsg.java | 2 +- .../org/thingsboard/server/actors/rpc/SessionActorInfo.java | 2 +- .../thingsboard/server/actors/ruleChain/DefaultTbContext.java | 2 +- .../server/actors/ruleChain/RemoteToRuleChainTellNextMsg.java | 2 +- .../thingsboard/server/actors/ruleChain/RuleChainActor.java | 2 +- .../actors/ruleChain/RuleChainActorMessageProcessor.java | 2 +- .../server/actors/ruleChain/RuleChainManagerActor.java | 2 +- .../server/actors/ruleChain/RuleChainToRuleChainMsg.java | 2 +- .../server/actors/ruleChain/RuleChainToRuleNodeMsg.java | 2 +- .../org/thingsboard/server/actors/ruleChain/RuleNodeActor.java | 2 +- .../server/actors/ruleChain/RuleNodeActorMessageProcessor.java | 2 +- .../org/thingsboard/server/actors/ruleChain/RuleNodeCtx.java | 2 +- .../thingsboard/server/actors/ruleChain/RuleNodeRelation.java | 2 +- .../actors/ruleChain/RuleNodeToRuleChainTellNextMsg.java | 2 +- .../server/actors/ruleChain/RuleNodeToSelfErrorMsg.java | 2 +- .../thingsboard/server/actors/ruleChain/RuleNodeToSelfMsg.java | 2 +- .../org/thingsboard/server/actors/service/ActorService.java | 2 +- .../org/thingsboard/server/actors/service/ComponentActor.java | 2 +- .../thingsboard/server/actors/service/ContextAwareActor.java | 2 +- .../thingsboard/server/actors/service/ContextBasedCreator.java | 2 +- .../thingsboard/server/actors/service/DefaultActorService.java | 2 +- .../server/actors/shared/AbstractContextAwareMsgProcessor.java | 2 +- .../thingsboard/server/actors/shared/ActorTerminationMsg.java | 2 +- .../server/actors/shared/ComponentMsgProcessor.java | 2 +- .../thingsboard/server/actors/shared/EntityActorsManager.java | 2 +- .../server/actors/shared/rulechain/RuleChainManager.java | 2 +- .../server/actors/shared/rulechain/SystemRuleChainManager.java | 2 +- .../server/actors/shared/rulechain/TenantRuleChainManager.java | 2 +- .../java/org/thingsboard/server/actors/stats/StatsActor.java | 2 +- .../org/thingsboard/server/actors/stats/StatsPersistMsg.java | 2 +- .../org/thingsboard/server/actors/stats/StatsPersistTick.java | 2 +- .../thingsboard/server/actors/tenant/DebugTbRateLimits.java | 2 +- .../java/org/thingsboard/server/actors/tenant/TenantActor.java | 2 +- .../org/thingsboard/server/config/AuditLogLevelProperties.java | 2 +- .../main/java/org/thingsboard/server/config/JwtSettings.java | 2 +- .../java/org/thingsboard/server/config/MvcCorsProperties.java | 2 +- .../thingsboard/server/config/RateLimitProcessingFilter.java | 2 +- .../org/thingsboard/server/config/SchedulingConfiguration.java | 2 +- .../org/thingsboard/server/config/SwaggerConfiguration.java | 2 +- .../server/config/ThingsboardMessageConfiguration.java | 2 +- .../server/config/ThingsboardSecurityConfiguration.java | 2 +- .../src/main/java/org/thingsboard/server/config/WebConfig.java | 2 +- .../org/thingsboard/server/config/WebSocketConfiguration.java | 2 +- .../org/thingsboard/server/controller/AdminController.java | 2 +- .../org/thingsboard/server/controller/AlarmController.java | 2 +- .../org/thingsboard/server/controller/AssetController.java | 2 +- .../org/thingsboard/server/controller/AuditLogController.java | 2 +- .../java/org/thingsboard/server/controller/AuthController.java | 2 +- .../java/org/thingsboard/server/controller/BaseController.java | 2 +- .../server/controller/ComponentDescriptorController.java | 2 +- .../org/thingsboard/server/controller/CustomerController.java | 2 +- .../org/thingsboard/server/controller/DashboardController.java | 2 +- .../org/thingsboard/server/controller/DeviceController.java | 2 +- .../server/controller/EntityRelationController.java | 2 +- .../thingsboard/server/controller/EntityViewController.java | 2 +- .../org/thingsboard/server/controller/EventController.java | 2 +- .../thingsboard/server/controller/HttpValidationCallback.java | 2 +- .../java/org/thingsboard/server/controller/RpcController.java | 2 +- .../org/thingsboard/server/controller/RuleChainController.java | 2 +- .../java/org/thingsboard/server/controller/TbUrlConstants.java | 2 +- .../org/thingsboard/server/controller/TelemetryController.java | 2 +- .../org/thingsboard/server/controller/TenantController.java | 2 +- .../java/org/thingsboard/server/controller/UserController.java | 2 +- .../thingsboard/server/controller/WidgetTypeController.java | 2 +- .../thingsboard/server/controller/WidgetsBundleController.java | 2 +- .../server/controller/plugin/TbWebSocketHandler.java | 2 +- .../exception/ThingsboardCredentialsExpiredResponse.java | 2 +- .../thingsboard/server/exception/ThingsboardErrorResponse.java | 2 +- .../server/exception/ThingsboardErrorResponseHandler.java | 2 +- .../server/install/ThingsboardInstallConfiguration.java | 2 +- .../server/install/ThingsboardInstallException.java | 2 +- .../thingsboard/server/install/ThingsboardInstallService.java | 2 +- .../cluster/discovery/CurrentServerInstanceService.java | 2 +- .../server/service/cluster/discovery/DiscoveryService.java | 2 +- .../service/cluster/discovery/DiscoveryServiceListener.java | 2 +- .../service/cluster/discovery/DummyDiscoveryService.java | 2 +- .../server/service/cluster/discovery/ServerInstance.java | 2 +- .../service/cluster/discovery/ServerInstanceService.java | 2 +- .../server/service/cluster/discovery/ZkDiscoveryService.java | 2 +- .../server/service/cluster/routing/ClusterRoutingService.java | 2 +- .../cluster/routing/ConsistentClusterRoutingService.java | 2 +- .../server/service/cluster/routing/ConsistentHashCircle.java | 2 +- .../server/service/cluster/rpc/ClusterGrpcService.java | 2 +- .../server/service/cluster/rpc/ClusterRpcService.java | 2 +- .../thingsboard/server/service/cluster/rpc/GrpcSession.java | 2 +- .../server/service/cluster/rpc/GrpcSessionListener.java | 2 +- .../thingsboard/server/service/cluster/rpc/RpcMsgListener.java | 2 +- .../service/component/AnnotationComponentDiscoveryService.java | 2 +- .../server/service/component/ComponentDiscoveryService.java | 2 +- .../server/service/encoding/DataDecodingEncodingService.java | 2 +- .../server/service/encoding/ProtoWithFSTService.java | 2 +- .../server/service/environment/EnvironmentLogService.java | 2 +- .../service/executors/ClusterRpcCallbackExecutorService.java | 2 +- .../server/service/executors/DbCallbackExecutorService.java | 2 +- .../server/service/executors/ExternalCallExecutorService.java | 2 +- .../server/service/executors/SharedEventLoopGroupService.java | 3 +-- .../install/CassandraAbstractDatabaseSchemaService.java | 2 +- .../service/install/CassandraDatabaseUpgradeService.java | 2 +- .../service/install/CassandraEntityDatabaseSchemaService.java | 2 +- .../service/install/CassandraTsDatabaseSchemaService.java | 2 +- .../org/thingsboard/server/service/install/DatabaseHelper.java | 2 +- .../server/service/install/DatabaseSchemaService.java | 2 +- .../server/service/install/DatabaseUpgradeService.java | 2 +- .../server/service/install/DefaultSystemDataLoaderService.java | 2 +- .../server/service/install/EntityDatabaseSchemaService.java | 2 +- .../org/thingsboard/server/service/install/InstallScripts.java | 2 +- .../service/install/SqlAbstractDatabaseSchemaService.java | 2 +- .../server/service/install/SqlDatabaseUpgradeService.java | 2 +- .../server/service/install/SqlEntityDatabaseSchemaService.java | 2 +- .../service/install/SqlTimescaleDatabaseSchemaService.java | 2 +- .../server/service/install/SqlTsDatabaseSchemaService.java | 2 +- .../server/service/install/SystemDataLoaderService.java | 2 +- .../server/service/install/TsDatabaseSchemaService.java | 2 +- .../server/service/install/cql/CQLStatementsParser.java | 2 +- .../server/service/install/cql/CassandraDbHelper.java | 2 +- .../thingsboard/server/service/install/sql/SqlDbHelper.java | 2 +- .../server/service/install/update/DataUpdateService.java | 2 +- .../service/install/update/DefaultDataUpdateService.java | 2 +- .../server/service/install/update/PaginatedUpdater.java | 2 +- .../thingsboard/server/service/mail/DefaultMailService.java | 2 +- .../thingsboard/server/service/mail/MailExecutorService.java | 2 +- .../server/service/rpc/DefaultDeviceRpcService.java | 2 +- .../org/thingsboard/server/service/rpc/DeviceRpcService.java | 2 +- .../thingsboard/server/service/rpc/FromDeviceRpcResponse.java | 2 +- .../thingsboard/server/service/rpc/LocalRequestMetaData.java | 2 +- .../server/service/rpc/ToDeviceRpcRequestActorMsg.java | 2 +- .../server/service/rpc/ToServerRpcResponseActorMsg.java | 2 +- .../server/service/script/AbstractJsInvokeService.java | 2 +- .../server/service/script/AbstractNashornJsInvokeService.java | 2 +- .../thingsboard/server/service/script/JsExecutorService.java | 2 +- .../org/thingsboard/server/service/script/JsInvokeRequest.java | 2 +- .../thingsboard/server/service/script/JsInvokeResponse.java | 2 +- .../org/thingsboard/server/service/script/JsInvokeService.java | 2 +- .../org/thingsboard/server/service/script/JsScriptType.java | 2 +- .../org/thingsboard/server/service/script/JsStatCallback.java | 2 +- .../server/service/script/NashornJsInvokeService.java | 2 +- .../server/service/script/RemoteJsInvokeService.java | 2 +- .../server/service/script/RemoteJsRequestEncoder.java | 2 +- .../server/service/script/RemoteJsResponseDecoder.java | 2 +- .../server/service/script/RuleNodeJsScriptEngine.java | 2 +- .../server/service/script/RuleNodeScriptFactory.java | 2 +- .../thingsboard/server/service/security/AccessValidator.java | 2 +- .../server/service/security/ValidationCallback.java | 2 +- .../thingsboard/server/service/security/ValidationResult.java | 2 +- .../server/service/security/ValidationResultCode.java | 2 +- .../service/security/auth/AbstractJwtAuthenticationToken.java | 2 +- .../server/service/security/auth/JwtAuthenticationToken.java | 2 +- .../service/security/auth/RefreshAuthenticationToken.java | 2 +- .../service/security/auth/jwt/JwtAuthenticationProvider.java | 2 +- .../auth/jwt/JwtTokenAuthenticationProcessingFilter.java | 2 +- .../security/auth/jwt/RefreshTokenAuthenticationProvider.java | 2 +- .../security/auth/jwt/RefreshTokenProcessingFilter.java | 2 +- .../service/security/auth/jwt/RefreshTokenRepository.java | 2 +- .../server/service/security/auth/jwt/RefreshTokenRequest.java | 2 +- .../service/security/auth/jwt/SkipPathRequestMatcher.java | 2 +- .../security/auth/jwt/extractor/JwtHeaderTokenExtractor.java | 2 +- .../security/auth/jwt/extractor/JwtQueryTokenExtractor.java | 2 +- .../service/security/auth/jwt/extractor/TokenExtractor.java | 2 +- .../server/service/security/auth/rest/LoginRequest.java | 2 +- .../server/service/security/auth/rest/PublicLoginRequest.java | 2 +- .../service/security/auth/rest/RestAuthenticationDetails.java | 3 +-- .../security/auth/rest/RestAuthenticationDetailsSource.java | 3 +-- .../service/security/auth/rest/RestAuthenticationProvider.java | 2 +- .../auth/rest/RestAwareAuthenticationFailureHandler.java | 2 +- .../auth/rest/RestAwareAuthenticationSuccessHandler.java | 2 +- .../service/security/auth/rest/RestLoginProcessingFilter.java | 2 +- .../security/auth/rest/RestPublicLoginProcessingFilter.java | 2 +- .../service/security/device/DefaultDeviceAuthService.java | 2 +- .../security/exception/AuthMethodNotSupportedException.java | 2 +- .../service/security/exception/JwtExpiredTokenException.java | 2 +- .../security/exception/UserPasswordExpiredException.java | 2 +- .../server/service/security/model/SecurityUser.java | 2 +- .../server/service/security/model/UserPrincipal.java | 2 +- .../server/service/security/model/token/AccessJwtToken.java | 2 +- .../server/service/security/model/token/JwtToken.java | 2 +- .../server/service/security/model/token/JwtTokenFactory.java | 2 +- .../server/service/security/model/token/RawAccessJwtToken.java | 2 +- .../service/security/permission/AbstractPermissions.java | 2 +- .../service/security/permission/AccessControlService.java | 2 +- .../service/security/permission/CustomerUserPermissions.java | 2 +- .../security/permission/DefaultAccessControlService.java | 2 +- .../server/service/security/permission/Operation.java | 2 +- .../server/service/security/permission/PermissionChecker.java | 2 +- .../server/service/security/permission/Permissions.java | 2 +- .../server/service/security/permission/Resource.java | 2 +- .../service/security/permission/SysAdminPermissions.java | 2 +- .../service/security/permission/TenantAdminPermissions.java | 2 +- .../service/security/system/DefaultSystemSecurityService.java | 2 +- .../server/service/security/system/SystemSecurityService.java | 2 +- .../service/session/DefaultDeviceSessionCacheService.java | 2 +- .../server/service/session/DeviceSessionCacheService.java | 2 +- .../server/service/state/DefaultDeviceStateService.java | 2 +- .../java/org/thingsboard/server/service/state/DeviceState.java | 2 +- .../org/thingsboard/server/service/state/DeviceStateData.java | 2 +- .../thingsboard/server/service/state/DeviceStateService.java | 2 +- .../thingsboard/server/service/telemetry/AttributeData.java | 2 +- .../service/telemetry/DefaultTelemetrySubscriptionService.java | 2 +- .../service/telemetry/DefaultTelemetryWebSocketService.java | 2 +- .../org/thingsboard/server/service/telemetry/SessionEvent.java | 2 +- .../thingsboard/server/service/telemetry/TelemetryFeature.java | 2 +- .../server/service/telemetry/TelemetrySubscriptionService.java | 2 +- .../service/telemetry/TelemetryWebSocketMsgEndpoint.java | 2 +- .../server/service/telemetry/TelemetryWebSocketService.java | 2 +- .../server/service/telemetry/TelemetryWebSocketSessionRef.java | 2 +- .../server/service/telemetry/TelemetryWebSocketTextMsg.java | 2 +- .../java/org/thingsboard/server/service/telemetry/TsData.java | 2 +- .../server/service/telemetry/WsSessionMetaData.java | 2 +- .../service/telemetry/cmd/AttributesSubscriptionCmd.java | 2 +- .../server/service/telemetry/cmd/GetHistoryCmd.java | 2 +- .../server/service/telemetry/cmd/SubscriptionCmd.java | 2 +- .../server/service/telemetry/cmd/TelemetryPluginCmd.java | 2 +- .../service/telemetry/cmd/TelemetryPluginCmdsWrapper.java | 2 +- .../service/telemetry/cmd/TimeseriesSubscriptionCmd.java | 2 +- .../service/telemetry/exception/AccessDeniedException.java | 2 +- .../service/telemetry/exception/EntityNotFoundException.java | 2 +- .../service/telemetry/exception/InternalErrorException.java | 2 +- .../telemetry/exception/InvalidParametersException.java | 2 +- .../service/telemetry/exception/ToErrorResponseEntity.java | 2 +- .../service/telemetry/exception/UnauthorizedException.java | 2 +- .../service/telemetry/exception/UncheckedApiException.java | 2 +- .../thingsboard/server/service/telemetry/sub/Subscription.java | 2 +- .../server/service/telemetry/sub/SubscriptionErrorCode.java | 2 +- .../server/service/telemetry/sub/SubscriptionState.java | 2 +- .../server/service/telemetry/sub/SubscriptionUpdate.java | 2 +- .../service/transaction/BaseRuleChainTransactionService.java | 2 +- .../server/service/transaction/TbTransactionTask.java | 2 +- .../server/service/transport/LocalTransportApiService.java | 2 +- .../server/service/transport/LocalTransportService.java | 2 +- .../service/transport/RemoteRuleEngineTransportService.java | 2 +- .../server/service/transport/RemoteTransportApiService.java | 2 +- .../thingsboard/server/service/transport/RuleEngineStats.java | 2 +- .../server/service/transport/RuleEngineTransportService.java | 2 +- .../server/service/transport/ToRuleEngineMsgDecoder.java | 2 +- .../server/service/transport/ToTransportMsgEncoder.java | 2 +- .../server/service/transport/TransportApiRequestDecoder.java | 2 +- .../server/service/transport/TransportApiResponseEncoder.java | 2 +- .../server/service/transport/TransportApiService.java | 2 +- .../transport/msg/TransportToDeviceActorMsgWrapper.java | 2 +- .../server/service/update/DefaultUpdateService.java | 2 +- .../org/thingsboard/server/service/update/UpdateService.java | 2 +- .../src/main/java/org/thingsboard/server/utils/MiscUtils.java | 2 +- application/src/main/proto/cluster.proto | 2 +- application/src/main/proto/jsinvoke.proto | 2 +- application/src/main/resources/actor-system.conf | 2 +- application/src/main/resources/logback.xml | 2 +- application/src/main/resources/templates/account.activated.vm | 2 +- application/src/main/resources/templates/account.lockout.vm | 2 +- application/src/main/resources/templates/activation.vm | 2 +- application/src/main/resources/templates/password.was.reset.vm | 2 +- application/src/main/resources/templates/reset.password.vm | 2 +- application/src/main/resources/templates/test.vm | 2 +- application/src/main/resources/thingsboard.yml | 2 +- application/src/main/scripts/install/install.sh | 2 +- application/src/main/scripts/install/install_dev_db.sh | 2 +- application/src/main/scripts/install/logback.xml | 2 +- application/src/main/scripts/install/upgrade.sh | 2 +- application/src/main/scripts/install/upgrade_dev_db.sh | 2 +- .../thingsboard/server/controller/AbstractControllerTest.java | 2 +- .../server/controller/AbstractRuleEngineControllerTest.java | 2 +- .../thingsboard/server/controller/BaseAdminControllerTest.java | 2 +- .../thingsboard/server/controller/BaseAssetControllerTest.java | 2 +- .../server/controller/BaseAuditLogControllerTest.java | 2 +- .../thingsboard/server/controller/BaseAuthControllerTest.java | 2 +- .../controller/BaseComponentDescriptorControllerTest.java | 2 +- .../server/controller/BaseCustomerControllerTest.java | 2 +- .../server/controller/BaseDashboardControllerTest.java | 2 +- .../server/controller/BaseDeviceControllerTest.java | 2 +- .../server/controller/BaseEntityViewControllerTest.java | 2 +- .../server/controller/BaseTenantControllerTest.java | 2 +- .../thingsboard/server/controller/BaseUserControllerTest.java | 2 +- .../server/controller/BaseWidgetTypeControllerTest.java | 2 +- .../server/controller/BaseWidgetsBundleControllerTest.java | 2 +- .../server/controller/ControllerNoSqlTestSuite.java | 2 +- .../thingsboard/server/controller/ControllerSqlTestSuite.java | 2 +- .../server/controller/nosql/AdminControllerNoSqlTest.java | 2 +- .../server/controller/nosql/AssetControllerNoSqlTest.java | 2 +- .../server/controller/nosql/AuditLogControllerNoSqlTest.java | 2 +- .../server/controller/nosql/AuthControllerNoSqlTest.java | 2 +- .../nosql/ComponentDescriptorControllerNoSqlTest.java | 2 +- .../server/controller/nosql/CustomerControllerNoSqlTest.java | 2 +- .../server/controller/nosql/DashboardControllerNoSqlTest.java | 2 +- .../server/controller/nosql/DeviceControllerNoSqlTest.java | 2 +- .../server/controller/nosql/EntityViewControllerNoSqlTest.java | 2 +- .../server/controller/nosql/TenantControllerNoSqlTest.java | 2 +- .../server/controller/nosql/UserControllerNoSqlTest.java | 2 +- .../server/controller/nosql/WidgetTypeControllerNoSqlTest.java | 2 +- .../controller/nosql/WidgetsBundleControllerNoSqlTest.java | 2 +- .../server/controller/sql/AdminControllerSqlTest.java | 2 +- .../server/controller/sql/AssetControllerSqlTest.java | 2 +- .../server/controller/sql/AuditLogControllerSqlTest.java | 2 +- .../server/controller/sql/AuthControllerSqlTest.java | 2 +- .../controller/sql/ComponentDescriptorControllerSqlTest.java | 2 +- .../server/controller/sql/CustomerControllerSqlTest.java | 2 +- .../server/controller/sql/DashboardControllerSqlTest.java | 2 +- .../server/controller/sql/DeviceControllerSqlTest.java | 2 +- .../server/controller/sql/EntityViewControllerSqlTest.java | 2 +- .../server/controller/sql/TenantControllerSqlTest.java | 2 +- .../server/controller/sql/UserControllerSqlTest.java | 2 +- .../server/controller/sql/WidgetTypeControllerSqlTest.java | 2 +- .../server/controller/sql/WidgetsBundleControllerSqlTest.java | 2 +- .../org/thingsboard/server/mqtt/DbConfigurationTestRule.java | 2 +- .../java/org/thingsboard/server/mqtt/MqttNoSqlTestSuite.java | 2 +- .../java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java | 2 +- .../mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java | 2 +- .../mqtt/rpc/nosql/MqttServerSideRpcNoSqlIntegrationTest.java | 2 +- .../mqtt/rpc/sql/MqttServerSideRpcSqlIntegrationTest.java | 2 +- .../mqtt/telemetry/AbstractMqttTelemetryIntegrationTest.java | 2 +- .../telemetry/nosql/MqttTelemetryNoSqlIntegrationTest.java | 2 +- .../mqtt/telemetry/sql/MqttTelemetrySqlIntegrationTest.java | 2 +- .../org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java | 2 +- .../org/thingsboard/server/rules/RuleEngineSqlTestSuite.java | 2 +- .../rules/flow/AbstractRuleEngineFlowIntegrationTest.java | 2 +- .../rules/flow/nosql/RuleEngineFlowNoSqlIntegrationTest.java | 2 +- .../rules/flow/sql/RuleEngineFlowSqlIntegrationTest.java | 2 +- .../lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java | 2 +- .../nosql/RuleEngineLifecycleNoSqlIntegrationTest.java | 2 +- .../lifecycle/sql/RuleEngineLifecycleSqlIntegrationTest.java | 2 +- .../cluster/routing/ConsistentClusterRoutingServiceTest.java | 2 +- .../org/thingsboard/server/service/mail/TestMailService.java | 2 +- .../server/service/script/RuleNodeJsScriptEngineTest.java | 2 +- .../server/service/script/TestNashornJsInvokeService.java | 2 +- .../org/thingsboard/server/system/BaseHttpDeviceApiTest.java | 2 +- .../org/thingsboard/server/system/SystemNoSqlTestSuite.java | 2 +- .../java/org/thingsboard/server/system/SystemSqlTestSuite.java | 2 +- .../thingsboard/server/system/nosql/DeviceApiNoSqlTest.java | 2 +- .../org/thingsboard/server/system/sql/DeviceApiSqlTest.java | 2 +- common/dao-api/pom.xml | 2 +- .../java/org/thingsboard/server/dao/alarm/AlarmService.java | 2 +- .../java/org/thingsboard/server/dao/asset/AssetService.java | 2 +- .../thingsboard/server/dao/attributes/AttributesService.java | 2 +- .../java/org/thingsboard/server/dao/audit/AuditLogService.java | 2 +- .../server/dao/cassandra/AbstractCassandraCluster.java | 2 +- .../org/thingsboard/server/dao/cassandra/CassandraCluster.java | 2 +- .../server/dao/cassandra/CassandraInstallCluster.java | 2 +- .../server/dao/cassandra/CassandraQueryOptions.java | 2 +- .../server/dao/cassandra/CassandraSocketOptions.java | 2 +- .../server/dao/component/ComponentDescriptorService.java | 2 +- .../org/thingsboard/server/dao/customer/CustomerService.java | 2 +- .../org/thingsboard/server/dao/dashboard/DashboardService.java | 2 +- .../org/thingsboard/server/dao/device/ClaimDevicesService.java | 2 +- .../server/dao/device/DeviceCredentialsService.java | 2 +- .../java/org/thingsboard/server/dao/device/DeviceService.java | 2 +- .../org/thingsboard/server/dao/device/claim/ClaimData.java | 2 +- .../org/thingsboard/server/dao/device/claim/ClaimResponse.java | 2 +- .../org/thingsboard/server/dao/device/claim/ClaimResult.java | 2 +- .../java/org/thingsboard/server/dao/entity/EntityService.java | 2 +- .../thingsboard/server/dao/entityview/EntityViewService.java | 2 +- .../java/org/thingsboard/server/dao/event/EventService.java | 2 +- .../thingsboard/server/dao/nosql/CassandraStatementTask.java | 2 +- .../org/thingsboard/server/dao/relation/RelationService.java | 2 +- .../java/org/thingsboard/server/dao/rule/RuleChainService.java | 2 +- .../thingsboard/server/dao/settings/AdminSettingsService.java | 2 +- .../java/org/thingsboard/server/dao/tenant/TenantService.java | 2 +- .../thingsboard/server/dao/timeseries/TimeseriesService.java | 2 +- .../main/java/org/thingsboard/server/dao/user/UserService.java | 2 +- .../main/java/org/thingsboard/server/dao/util/AsyncTask.java | 2 +- .../src/main/java/org/thingsboard/server/dao/util/HsqlDao.java | 2 +- .../main/java/org/thingsboard/server/dao/util/NoSqlAnyDao.java | 2 +- .../main/java/org/thingsboard/server/dao/util/NoSqlDao.java | 2 +- .../main/java/org/thingsboard/server/dao/util/NoSqlTsDao.java | 2 +- .../src/main/java/org/thingsboard/server/dao/util/PsqlDao.java | 2 +- .../src/main/java/org/thingsboard/server/dao/util/SqlDao.java | 2 +- .../main/java/org/thingsboard/server/dao/util/SqlTsDao.java | 2 +- .../org/thingsboard/server/dao/widget/WidgetTypeService.java | 2 +- .../thingsboard/server/dao/widget/WidgetsBundleService.java | 2 +- common/data/pom.xml | 2 +- .../java/org/thingsboard/server/common/data/AdminSettings.java | 2 +- .../main/java/org/thingsboard/server/common/data/BaseData.java | 2 +- .../org/thingsboard/server/common/data/CacheConstants.java | 2 +- .../java/org/thingsboard/server/common/data/ClaimRequest.java | 2 +- .../java/org/thingsboard/server/common/data/ContactBased.java | 2 +- .../main/java/org/thingsboard/server/common/data/Customer.java | 2 +- .../java/org/thingsboard/server/common/data/Dashboard.java | 2 +- .../java/org/thingsboard/server/common/data/DashboardInfo.java | 2 +- .../java/org/thingsboard/server/common/data/DataConstants.java | 2 +- .../main/java/org/thingsboard/server/common/data/Device.java | 2 +- .../org/thingsboard/server/common/data/EntityFieldsData.java | 2 +- .../java/org/thingsboard/server/common/data/EntitySubtype.java | 2 +- .../java/org/thingsboard/server/common/data/EntityType.java | 2 +- .../java/org/thingsboard/server/common/data/EntityView.java | 2 +- .../main/java/org/thingsboard/server/common/data/Event.java | 2 +- .../org/thingsboard/server/common/data/HasAdditionalInfo.java | 2 +- .../java/org/thingsboard/server/common/data/HasCustomerId.java | 2 +- .../main/java/org/thingsboard/server/common/data/HasName.java | 2 +- .../java/org/thingsboard/server/common/data/HasTenantId.java | 2 +- .../org/thingsboard/server/common/data/SearchTextBased.java | 2 +- .../server/common/data/SearchTextBasedWithAdditionalInfo.java | 2 +- .../org/thingsboard/server/common/data/ShortCustomerInfo.java | 2 +- .../main/java/org/thingsboard/server/common/data/Tenant.java | 2 +- .../java/org/thingsboard/server/common/data/UUIDConverter.java | 2 +- .../java/org/thingsboard/server/common/data/UpdateMessage.java | 2 +- .../src/main/java/org/thingsboard/server/common/data/User.java | 2 +- .../java/org/thingsboard/server/common/data/alarm/Alarm.java | 2 +- .../java/org/thingsboard/server/common/data/alarm/AlarmId.java | 2 +- .../org/thingsboard/server/common/data/alarm/AlarmInfo.java | 2 +- .../org/thingsboard/server/common/data/alarm/AlarmQuery.java | 2 +- .../server/common/data/alarm/AlarmSearchStatus.java | 2 +- .../thingsboard/server/common/data/alarm/AlarmSeverity.java | 2 +- .../org/thingsboard/server/common/data/alarm/AlarmStatus.java | 2 +- .../java/org/thingsboard/server/common/data/asset/Asset.java | 2 +- .../thingsboard/server/common/data/asset/AssetSearchQuery.java | 2 +- .../org/thingsboard/server/common/data/audit/ActionStatus.java | 2 +- .../org/thingsboard/server/common/data/audit/ActionType.java | 2 +- .../org/thingsboard/server/common/data/audit/AuditLog.java | 2 +- .../server/common/data/device/DeviceSearchQuery.java | 2 +- .../server/common/data/entityview/EntityViewSearchQuery.java | 2 +- .../server/common/data/exception/ThingsboardErrorCode.java | 2 +- .../server/common/data/exception/ThingsboardException.java | 2 +- .../org/thingsboard/server/common/data/id/AdminSettingsId.java | 2 +- .../java/org/thingsboard/server/common/data/id/AssetId.java | 2 +- .../java/org/thingsboard/server/common/data/id/AuditLogId.java | 2 +- .../server/common/data/id/ComponentDescriptorId.java | 2 +- .../java/org/thingsboard/server/common/data/id/CustomerId.java | 2 +- .../org/thingsboard/server/common/data/id/DashboardId.java | 2 +- .../thingsboard/server/common/data/id/DeviceCredentialsId.java | 2 +- .../java/org/thingsboard/server/common/data/id/DeviceId.java | 2 +- .../java/org/thingsboard/server/common/data/id/EntityId.java | 2 +- .../server/common/data/id/EntityIdDeserializer.java | 2 +- .../org/thingsboard/server/common/data/id/EntityIdFactory.java | 2 +- .../thingsboard/server/common/data/id/EntityIdSerializer.java | 2 +- .../org/thingsboard/server/common/data/id/EntityViewId.java | 2 +- .../java/org/thingsboard/server/common/data/id/EventId.java | 2 +- .../java/org/thingsboard/server/common/data/id/IdBased.java | 2 +- .../java/org/thingsboard/server/common/data/id/NodeId.java | 2 +- .../org/thingsboard/server/common/data/id/RuleChainId.java | 2 +- .../java/org/thingsboard/server/common/data/id/RuleNodeId.java | 2 +- .../java/org/thingsboard/server/common/data/id/TenantId.java | 2 +- .../java/org/thingsboard/server/common/data/id/UUIDBased.java | 2 +- .../thingsboard/server/common/data/id/UserCredentialsId.java | 2 +- .../java/org/thingsboard/server/common/data/id/UserId.java | 2 +- .../org/thingsboard/server/common/data/id/WidgetTypeId.java | 2 +- .../org/thingsboard/server/common/data/id/WidgetsBundleId.java | 2 +- .../org/thingsboard/server/common/data/kv/Aggregation.java | 2 +- .../org/thingsboard/server/common/data/kv/AttributeKey.java | 2 +- .../thingsboard/server/common/data/kv/AttributeKvEntry.java | 2 +- .../server/common/data/kv/BaseAttributeKvEntry.java | 2 +- .../thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java | 2 +- .../thingsboard/server/common/data/kv/BaseReadTsKvQuery.java | 2 +- .../org/thingsboard/server/common/data/kv/BaseTsKvQuery.java | 2 +- .../org/thingsboard/server/common/data/kv/BasicKvEntry.java | 2 +- .../org/thingsboard/server/common/data/kv/BasicTsKvEntry.java | 2 +- .../thingsboard/server/common/data/kv/BooleanDataEntry.java | 2 +- .../java/org/thingsboard/server/common/data/kv/DataType.java | 2 +- .../org/thingsboard/server/common/data/kv/DeleteTsKvQuery.java | 2 +- .../org/thingsboard/server/common/data/kv/DoubleDataEntry.java | 2 +- .../java/org/thingsboard/server/common/data/kv/KvEntry.java | 2 +- .../org/thingsboard/server/common/data/kv/LongDataEntry.java | 2 +- .../org/thingsboard/server/common/data/kv/ReadTsKvQuery.java | 2 +- .../org/thingsboard/server/common/data/kv/StringDataEntry.java | 2 +- .../java/org/thingsboard/server/common/data/kv/TsKvEntry.java | 2 +- .../java/org/thingsboard/server/common/data/kv/TsKvQuery.java | 2 +- .../server/common/data/objects/AttributesEntityView.java | 2 +- .../server/common/data/objects/TelemetryEntityView.java | 2 +- .../org/thingsboard/server/common/data/page/BasePageLink.java | 2 +- .../thingsboard/server/common/data/page/PageDataIterable.java | 2 +- .../org/thingsboard/server/common/data/page/TextPageData.java | 2 +- .../org/thingsboard/server/common/data/page/TextPageLink.java | 2 +- .../org/thingsboard/server/common/data/page/TimePageData.java | 2 +- .../org/thingsboard/server/common/data/page/TimePageLink.java | 2 +- .../server/common/data/plugin/ComponentDescriptor.java | 2 +- .../server/common/data/plugin/ComponentLifecycleEvent.java | 2 +- .../server/common/data/plugin/ComponentLifecycleState.java | 2 +- .../thingsboard/server/common/data/plugin/ComponentScope.java | 2 +- .../thingsboard/server/common/data/plugin/ComponentType.java | 2 +- .../server/common/data/relation/EntityRelation.java | 2 +- .../server/common/data/relation/EntityRelationInfo.java | 2 +- .../server/common/data/relation/EntityRelationsQuery.java | 2 +- .../server/common/data/relation/EntitySearchDirection.java | 2 +- .../server/common/data/relation/EntityTypeFilter.java | 2 +- .../server/common/data/relation/RelationTypeGroup.java | 2 +- .../server/common/data/relation/RelationsSearchParameters.java | 2 +- .../org/thingsboard/server/common/data/rpc/RpcRequest.java | 2 +- .../server/common/data/rpc/ToDeviceRpcRequestBody.java | 2 +- .../server/common/data/rule/NodeConnectionInfo.java | 2 +- .../org/thingsboard/server/common/data/rule/RuleChain.java | 2 +- .../server/common/data/rule/RuleChainConnectionInfo.java | 2 +- .../thingsboard/server/common/data/rule/RuleChainMetaData.java | 2 +- .../java/org/thingsboard/server/common/data/rule/RuleNode.java | 2 +- .../java/org/thingsboard/server/common/data/rule/RuleType.java | 2 +- .../java/org/thingsboard/server/common/data/rule/Scope.java | 2 +- .../org/thingsboard/server/common/data/security/Authority.java | 2 +- .../server/common/data/security/DeviceCredentials.java | 2 +- .../server/common/data/security/DeviceCredentialsFilter.java | 2 +- .../server/common/data/security/DeviceCredentialsType.java | 2 +- .../server/common/data/security/DeviceTokenCredentials.java | 2 +- .../server/common/data/security/DeviceX509Credentials.java | 2 +- .../server/common/data/security/UserCredentials.java | 2 +- .../server/common/data/security/model/SecuritySettings.java | 2 +- .../server/common/data/security/model/UserPasswordPolicy.java | 2 +- .../org/thingsboard/server/common/data/widget/WidgetType.java | 2 +- .../thingsboard/server/common/data/widget/WidgetsBundle.java | 2 +- .../org/thingsboard/server/common/data/UUIDConverterTest.java | 2 +- common/message/pom.xml | 2 +- .../java/org/thingsboard/server/common/msg/EncryptionUtil.java | 2 +- .../main/java/org/thingsboard/server/common/msg/MsgType.java | 2 +- .../java/org/thingsboard/server/common/msg/TbActorMsg.java | 2 +- .../src/main/java/org/thingsboard/server/common/msg/TbMsg.java | 2 +- .../java/org/thingsboard/server/common/msg/TbMsgDataType.java | 2 +- .../java/org/thingsboard/server/common/msg/TbMsgMetaData.java | 2 +- .../thingsboard/server/common/msg/TbMsgTransactionData.java | 2 +- .../thingsboard/server/common/msg/aware/CustomerAwareMsg.java | 2 +- .../thingsboard/server/common/msg/aware/DeviceAwareMsg.java | 2 +- .../org/thingsboard/server/common/msg/aware/NodeAwareMsg.java | 2 +- .../thingsboard/server/common/msg/aware/RuleChainAwareMsg.java | 2 +- .../thingsboard/server/common/msg/aware/TenantAwareMsg.java | 2 +- .../thingsboard/server/common/msg/cluster/ClusterEventMsg.java | 2 +- .../server/common/msg/cluster/SendToClusterMsg.java | 2 +- .../thingsboard/server/common/msg/cluster/ServerAddress.java | 2 +- .../org/thingsboard/server/common/msg/cluster/ServerType.java | 2 +- .../thingsboard/server/common/msg/cluster/ToAllNodesMsg.java | 2 +- .../server/common/msg/core/ToServerRpcResponseMsg.java | 2 +- .../org/thingsboard/server/common/msg/kv/AttributesKVMsg.java | 2 +- .../thingsboard/server/common/msg/kv/BasicAttributeKVMsg.java | 2 +- .../server/common/msg/plugin/ComponentLifecycleMsg.java | 2 +- .../thingsboard/server/common/msg/rpc/ToDeviceRpcRequest.java | 2 +- .../org/thingsboard/server/common/msg/session/FeatureType.java | 2 +- .../thingsboard/server/common/msg/session/SessionContext.java | 2 +- .../thingsboard/server/common/msg/session/SessionMsgType.java | 2 +- .../common/msg/session/ex/ProcessingTimeoutException.java | 2 +- .../server/common/msg/session/ex/SessionAuthException.java | 2 +- .../server/common/msg/session/ex/SessionException.java | 2 +- .../server/common/msg/system/ServiceToRuleEngineMsg.java | 2 +- .../common/msg/timeout/DeviceActorClientSideRpcTimeoutMsg.java | 2 +- .../common/msg/timeout/DeviceActorServerSideRpcTimeoutMsg.java | 2 +- .../org/thingsboard/server/common/msg/timeout/TimeoutMsg.java | 2 +- .../org/thingsboard/server/common/msg/tools/TbRateLimits.java | 2 +- .../server/common/msg/tools/TbRateLimitsException.java | 2 +- common/message/src/main/proto/tbmsg.proto | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- .../org/thingsboard/server/kafka/AbstractTbKafkaTemplate.java | 2 +- .../org/thingsboard/server/kafka/AsyncCallbackTemplate.java | 2 +- .../main/java/org/thingsboard/server/kafka/TBKafkaAdmin.java | 2 +- .../org/thingsboard/server/kafka/TBKafkaConsumerTemplate.java | 2 +- .../org/thingsboard/server/kafka/TBKafkaProducerTemplate.java | 2 +- .../main/java/org/thingsboard/server/kafka/TbKafkaDecoder.java | 2 +- .../main/java/org/thingsboard/server/kafka/TbKafkaEncoder.java | 2 +- .../main/java/org/thingsboard/server/kafka/TbKafkaHandler.java | 2 +- .../java/org/thingsboard/server/kafka/TbKafkaPartitioner.java | 2 +- .../java/org/thingsboard/server/kafka/TbKafkaProperty.java | 2 +- .../thingsboard/server/kafka/TbKafkaRequestIdExtractor.java | 2 +- .../org/thingsboard/server/kafka/TbKafkaRequestTemplate.java | 2 +- .../org/thingsboard/server/kafka/TbKafkaResponseTemplate.java | 2 +- .../java/org/thingsboard/server/kafka/TbKafkaSettings.java | 2 +- .../java/org/thingsboard/server/kafka/TbNodeIdProvider.java | 2 +- common/transport/coap/pom.xml | 2 +- .../server/transport/coap/CoapTransportContext.java | 2 +- .../server/transport/coap/CoapTransportResource.java | 2 +- .../server/transport/coap/CoapTransportService.java | 2 +- .../server/transport/coap/adaptors/CoapTransportAdaptor.java | 2 +- .../server/transport/coap/adaptors/JsonCoapAdaptor.java | 2 +- .../server/transport/coap/client/DeviceEmulator.java | 2 +- common/transport/http/pom.xml | 2 +- .../thingsboard/server/transport/http/DeviceApiController.java | 2 +- .../server/transport/http/HttpTransportContext.java | 2 +- common/transport/mqtt/pom.xml | 2 +- .../server/transport/mqtt/MqttSslHandlerProvider.java | 2 +- .../java/org/thingsboard/server/transport/mqtt/MqttTopics.java | 2 +- .../server/transport/mqtt/MqttTransportContext.java | 2 +- .../server/transport/mqtt/MqttTransportHandler.java | 2 +- .../server/transport/mqtt/MqttTransportServerInitializer.java | 2 +- .../server/transport/mqtt/MqttTransportService.java | 2 +- .../server/transport/mqtt/adaptors/JsonMqttAdaptor.java | 2 +- .../server/transport/mqtt/adaptors/MqttTransportAdaptor.java | 2 +- .../server/transport/mqtt/session/DeviceSessionCtx.java | 2 +- .../server/transport/mqtt/session/GatewayDeviceSessionCtx.java | 2 +- .../server/transport/mqtt/session/GatewaySessionHandler.java | 2 +- .../transport/mqtt/session/MqttDeviceAwareSessionContext.java | 2 +- .../server/transport/mqtt/session/MqttTopicMatcher.java | 2 +- .../org/thingsboard/server/transport/mqtt/util/SslUtil.java | 2 +- common/transport/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- .../server/common/transport/SessionMsgListener.java | 2 +- .../server/common/transport/SessionMsgProcessor.java | 2 +- .../thingsboard/server/common/transport/TransportAdaptor.java | 2 +- .../thingsboard/server/common/transport/TransportContext.java | 2 +- .../thingsboard/server/common/transport/TransportService.java | 2 +- .../server/common/transport/TransportServiceCallback.java | 2 +- .../server/common/transport/adaptor/AdaptorException.java | 2 +- .../server/common/transport/adaptor/JsonConverter.java | 2 +- .../server/common/transport/adaptor/JsonConverterConfig.java | 2 +- .../server/common/transport/auth/DeviceAuthResult.java | 2 +- .../server/common/transport/auth/DeviceAuthService.java | 2 +- .../common/transport/service/AbstractTransportService.java | 2 +- .../common/transport/service/RemoteTransportService.java | 2 +- .../server/common/transport/service/SessionMetaData.java | 2 +- .../common/transport/service/ToRuleEngineMsgEncoder.java | 2 +- .../transport/service/ToTransportMsgResponseDecoder.java | 2 +- .../common/transport/service/TransportApiRequestEncoder.java | 2 +- .../common/transport/service/TransportApiResponseDecoder.java | 2 +- .../common/transport/session/DeviceAwareSessionContext.java | 2 +- common/transport/transport-api/src/main/proto/transport.proto | 2 +- common/util/pom.xml | 2 +- .../org/thingsboard/common/util/AbstractListeningExecutor.java | 2 +- .../main/java/org/thingsboard/common/util/DonAsynchron.java | 2 +- .../java/org/thingsboard/common/util/ListeningExecutor.java | 2 +- .../org/thingsboard/common/util/ThingsBoardThreadFactory.java | 2 +- dao/pom.xml | 2 +- dao/src/main/java/org/thingsboard/server/dao/Dao.java | 2 +- dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java | 2 +- dao/src/main/java/org/thingsboard/server/dao/JpaDaoConfig.java | 2 +- .../main/java/org/thingsboard/server/dao/NoSqlDaoConfig.java | 2 +- .../main/java/org/thingsboard/server/dao/SqlTsDaoConfig.java | 2 +- .../java/org/thingsboard/server/dao/TimescaleDaoConfig.java | 2 +- .../main/java/org/thingsboard/server/dao/alarm/AlarmDao.java | 2 +- .../org/thingsboard/server/dao/alarm/BaseAlarmService.java | 2 +- .../org/thingsboard/server/dao/alarm/CassandraAlarmDao.java | 2 +- .../main/java/org/thingsboard/server/dao/asset/AssetDao.java | 2 +- .../java/org/thingsboard/server/dao/asset/AssetTypeFilter.java | 2 +- .../org/thingsboard/server/dao/asset/BaseAssetService.java | 2 +- .../org/thingsboard/server/dao/asset/CassandraAssetDao.java | 2 +- .../org/thingsboard/server/dao/attributes/AttributesDao.java | 2 +- .../server/dao/attributes/BaseAttributesService.java | 2 +- .../server/dao/attributes/CassandraBaseAttributesDao.java | 2 +- .../java/org/thingsboard/server/dao/audit/AuditLogDao.java | 2 +- .../org/thingsboard/server/dao/audit/AuditLogLevelFilter.java | 2 +- .../org/thingsboard/server/dao/audit/AuditLogLevelMask.java | 2 +- .../org/thingsboard/server/dao/audit/AuditLogQueryCursor.java | 2 +- .../org/thingsboard/server/dao/audit/AuditLogServiceImpl.java | 2 +- .../org/thingsboard/server/dao/audit/CassandraAuditLogDao.java | 2 +- .../thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java | 2 +- .../org/thingsboard/server/dao/audit/sink/AuditLogSink.java | 2 +- .../thingsboard/server/dao/audit/sink/DummyAuditLogSink.java | 2 +- .../server/dao/audit/sink/ElasticsearchAuditLogSink.java | 2 +- .../main/java/org/thingsboard/server/dao/cache/CacheSpecs.java | 2 +- .../server/dao/cache/CaffeineCacheConfiguration.java | 2 +- .../dao/cache/PreviousDeviceCredentialsIdKeyGenerator.java | 2 +- .../server/dao/cache/TBRedisCacheConfiguration.java | 2 +- .../server/dao/cache/TBRedisClusterConfiguration.java | 2 +- .../server/dao/cache/TBRedisStandaloneConfiguration.java | 2 +- .../server/dao/component/BaseComponentDescriptorService.java | 2 +- .../dao/component/CassandraBaseComponentDescriptorDao.java | 2 +- .../server/dao/component/ComponentDescriptorDao.java | 2 +- .../thingsboard/server/dao/customer/CassandraCustomerDao.java | 2 +- .../java/org/thingsboard/server/dao/customer/CustomerDao.java | 2 +- .../thingsboard/server/dao/customer/CustomerServiceImpl.java | 2 +- .../server/dao/dashboard/CassandraDashboardDao.java | 2 +- .../server/dao/dashboard/CassandraDashboardInfoDao.java | 2 +- .../org/thingsboard/server/dao/dashboard/DashboardDao.java | 2 +- .../org/thingsboard/server/dao/dashboard/DashboardInfoDao.java | 2 +- .../thingsboard/server/dao/dashboard/DashboardServiceImpl.java | 2 +- .../server/dao/device/CassandraDeviceCredentialsDao.java | 2 +- .../org/thingsboard/server/dao/device/CassandraDeviceDao.java | 2 +- .../java/org/thingsboard/server/dao/device/ClaimDataInfo.java | 2 +- .../thingsboard/server/dao/device/ClaimDevicesServiceImpl.java | 2 +- .../thingsboard/server/dao/device/DeviceCredentialsDao.java | 2 +- .../server/dao/device/DeviceCredentialsServiceImpl.java | 2 +- .../main/java/org/thingsboard/server/dao/device/DeviceDao.java | 2 +- .../org/thingsboard/server/dao/device/DeviceServiceImpl.java | 2 +- .../thingsboard/server/dao/entity/AbstractEntityService.java | 2 +- .../org/thingsboard/server/dao/entity/BaseEntityService.java | 2 +- .../server/dao/entityview/CassandraEntityViewDao.java | 2 +- .../org/thingsboard/server/dao/entityview/EntityViewDao.java | 2 +- .../server/dao/entityview/EntityViewServiceImpl.java | 2 +- .../org/thingsboard/server/dao/event/BaseEventService.java | 2 +- .../thingsboard/server/dao/event/CassandraBaseEventDao.java | 2 +- .../main/java/org/thingsboard/server/dao/event/EventDao.java | 2 +- .../thingsboard/server/dao/exception/BufferLimitException.java | 2 +- .../server/dao/exception/DataValidationException.java | 2 +- .../thingsboard/server/dao/exception/DatabaseException.java | 2 +- .../server/dao/exception/IncorrectParameterException.java | 2 +- .../main/java/org/thingsboard/server/dao/model/BaseEntity.java | 2 +- .../java/org/thingsboard/server/dao/model/BaseSqlEntity.java | 2 +- .../org/thingsboard/server/dao/model/EntitySubtypeEntity.java | 2 +- .../java/org/thingsboard/server/dao/model/ModelConstants.java | 2 +- .../org/thingsboard/server/dao/model/SearchTextEntity.java | 2 +- dao/src/main/java/org/thingsboard/server/dao/model/ToData.java | 2 +- .../server/dao/model/nosql/AdminSettingsEntity.java | 2 +- .../org/thingsboard/server/dao/model/nosql/AlarmEntity.java | 2 +- .../org/thingsboard/server/dao/model/nosql/AssetEntity.java | 2 +- .../org/thingsboard/server/dao/model/nosql/AuditLogEntity.java | 2 +- .../server/dao/model/nosql/ComponentDescriptorEntity.java | 2 +- .../org/thingsboard/server/dao/model/nosql/CustomerEntity.java | 2 +- .../thingsboard/server/dao/model/nosql/DashboardEntity.java | 2 +- .../server/dao/model/nosql/DashboardInfoEntity.java | 2 +- .../server/dao/model/nosql/DeviceCredentialsEntity.java | 2 +- .../org/thingsboard/server/dao/model/nosql/DeviceEntity.java | 2 +- .../thingsboard/server/dao/model/nosql/EntityViewEntity.java | 2 +- .../org/thingsboard/server/dao/model/nosql/EventEntity.java | 2 +- .../thingsboard/server/dao/model/nosql/RuleChainEntity.java | 2 +- .../org/thingsboard/server/dao/model/nosql/RuleNodeEntity.java | 2 +- .../org/thingsboard/server/dao/model/nosql/TenantEntity.java | 2 +- .../server/dao/model/nosql/UserCredentialsEntity.java | 2 +- .../org/thingsboard/server/dao/model/nosql/UserEntity.java | 2 +- .../thingsboard/server/dao/model/nosql/WidgetTypeEntity.java | 2 +- .../server/dao/model/nosql/WidgetsBundleEntity.java | 2 +- .../thingsboard/server/dao/model/sql/AbstractTsKvEntity.java | 2 +- .../thingsboard/server/dao/model/sql/AdminSettingsEntity.java | 2 +- .../java/org/thingsboard/server/dao/model/sql/AlarmEntity.java | 2 +- .../java/org/thingsboard/server/dao/model/sql/AssetEntity.java | 2 +- .../server/dao/model/sql/AttributeKvCompositeKey.java | 2 +- .../thingsboard/server/dao/model/sql/AttributeKvEntity.java | 2 +- .../org/thingsboard/server/dao/model/sql/AuditLogEntity.java | 2 +- .../server/dao/model/sql/ComponentDescriptorEntity.java | 2 +- .../org/thingsboard/server/dao/model/sql/CustomerEntity.java | 2 +- .../org/thingsboard/server/dao/model/sql/DashboardEntity.java | 2 +- .../thingsboard/server/dao/model/sql/DashboardInfoEntity.java | 2 +- .../server/dao/model/sql/DeviceCredentialsEntity.java | 2 +- .../org/thingsboard/server/dao/model/sql/DeviceEntity.java | 2 +- .../org/thingsboard/server/dao/model/sql/EntityViewEntity.java | 2 +- .../java/org/thingsboard/server/dao/model/sql/EventEntity.java | 2 +- .../thingsboard/server/dao/model/sql/RelationCompositeKey.java | 2 +- .../org/thingsboard/server/dao/model/sql/RelationEntity.java | 2 +- .../org/thingsboard/server/dao/model/sql/RuleChainEntity.java | 2 +- .../org/thingsboard/server/dao/model/sql/RuleNodeEntity.java | 2 +- .../org/thingsboard/server/dao/model/sql/TenantEntity.java | 2 +- .../server/dao/model/sql/UserCredentialsEntity.java | 2 +- .../java/org/thingsboard/server/dao/model/sql/UserEntity.java | 2 +- .../org/thingsboard/server/dao/model/sql/WidgetTypeEntity.java | 2 +- .../thingsboard/server/dao/model/sql/WidgetsBundleEntity.java | 2 +- .../dao/model/sqlts/timescale/TimescaleTsKvCompositeKey.java | 2 +- .../server/dao/model/sqlts/timescale/TimescaleTsKvEntity.java | 2 +- .../server/dao/model/sqlts/ts/TsKvCompositeKey.java | 2 +- .../org/thingsboard/server/dao/model/sqlts/ts/TsKvEntity.java | 2 +- .../server/dao/model/sqlts/ts/TsKvLatestCompositeKey.java | 2 +- .../server/dao/model/sqlts/ts/TsKvLatestEntity.java | 2 +- .../thingsboard/server/dao/model/type/ActionStatusCodec.java | 2 +- .../org/thingsboard/server/dao/model/type/ActionTypeCodec.java | 2 +- .../thingsboard/server/dao/model/type/AlarmSeverityCodec.java | 2 +- .../thingsboard/server/dao/model/type/AlarmStatusCodec.java | 2 +- .../org/thingsboard/server/dao/model/type/AuthorityCodec.java | 2 +- .../server/dao/model/type/ComponentLifecycleStateCodec.java | 2 +- .../thingsboard/server/dao/model/type/ComponentScopeCodec.java | 2 +- .../thingsboard/server/dao/model/type/ComponentTypeCodec.java | 2 +- .../server/dao/model/type/DeviceCredentialsTypeCodec.java | 2 +- .../org/thingsboard/server/dao/model/type/EntityTypeCodec.java | 2 +- .../java/org/thingsboard/server/dao/model/type/JsonCodec.java | 2 +- .../server/dao/model/type/RelationTypeGroupCodec.java | 2 +- .../thingsboard/server/dao/model/wrapper/EntityResultSet.java | 2 +- .../server/dao/nosql/CassandraAbstractAsyncDao.java | 2 +- .../org/thingsboard/server/dao/nosql/CassandraAbstractDao.java | 2 +- .../server/dao/nosql/CassandraAbstractModelDao.java | 2 +- .../server/dao/nosql/CassandraAbstractSearchTextDao.java | 2 +- .../server/dao/nosql/CassandraAbstractSearchTimeDao.java | 2 +- .../server/dao/nosql/CassandraBufferedRateExecutor.java | 2 +- .../server/dao/nosql/RateLimitedResultSetFuture.java | 2 +- .../org/thingsboard/server/dao/nosql/TbResultSetFuture.java | 2 +- .../org/thingsboard/server/dao/relation/BaseRelationDao.java | 2 +- .../thingsboard/server/dao/relation/BaseRelationService.java | 2 +- .../java/org/thingsboard/server/dao/relation/RelationDao.java | 2 +- .../org/thingsboard/server/dao/rule/BaseRuleChainService.java | 2 +- .../org/thingsboard/server/dao/rule/CassandraRuleChainDao.java | 2 +- .../org/thingsboard/server/dao/rule/CassandraRuleNodeDao.java | 2 +- .../java/org/thingsboard/server/dao/rule/RuleChainDao.java | 2 +- .../main/java/org/thingsboard/server/dao/rule/RuleNodeDao.java | 2 +- .../java/org/thingsboard/server/dao/service/DataValidator.java | 2 +- .../org/thingsboard/server/dao/service/PaginatedRemover.java | 2 +- .../thingsboard/server/dao/service/TimePaginatedRemover.java | 2 +- .../java/org/thingsboard/server/dao/service/Validator.java | 2 +- .../org/thingsboard/server/dao/settings/AdminSettingsDao.java | 2 +- .../server/dao/settings/AdminSettingsServiceImpl.java | 2 +- .../server/dao/settings/CassandraAdminSettingsDao.java | 2 +- .../java/org/thingsboard/server/dao/sql/JpaAbstractDao.java | 2 +- .../server/dao/sql/JpaAbstractDaoListeningExecutorService.java | 2 +- .../thingsboard/server/dao/sql/JpaAbstractSearchTextDao.java | 2 +- .../thingsboard/server/dao/sql/JpaAbstractSearchTimeDao.java | 2 +- .../org/thingsboard/server/dao/sql/JpaExecutorService.java | 2 +- .../server/dao/sql/ScheduledLogExecutorComponent.java | 2 +- .../org/thingsboard/server/dao/sql/TbSqlBlockingQueue.java | 2 +- .../thingsboard/server/dao/sql/TbSqlBlockingQueueParams.java | 2 +- .../main/java/org/thingsboard/server/dao/sql/TbSqlQueue.java | 2 +- .../java/org/thingsboard/server/dao/sql/TbSqlQueueElement.java | 2 +- .../org/thingsboard/server/dao/sql/alarm/AlarmRepository.java | 2 +- .../java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java | 2 +- .../org/thingsboard/server/dao/sql/asset/AssetRepository.java | 2 +- .../java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java | 2 +- .../server/dao/sql/attributes/AttributeKvInsertRepository.java | 2 +- .../server/dao/sql/attributes/AttributeKvRepository.java | 2 +- .../dao/sql/attributes/HsqlAttributesInsertRepository.java | 2 +- .../thingsboard/server/dao/sql/attributes/JpaAttributeDao.java | 2 +- .../dao/sql/attributes/PsqlAttributesInsertRepository.java | 2 +- .../thingsboard/server/dao/sql/audit/AuditLogRepository.java | 2 +- .../org/thingsboard/server/dao/sql/audit/JpaAuditLogDao.java | 2 +- .../component/AbstractComponentDescriptorInsertRepository.java | 2 +- .../dao/sql/component/ComponentDescriptorInsertRepository.java | 2 +- .../dao/sql/component/ComponentDescriptorRepository.java | 2 +- .../sql/component/HsqlComponentDescriptorInsertRepository.java | 2 +- .../dao/sql/component/JpaBaseComponentDescriptorDao.java | 2 +- .../sql/component/PsqlComponentDescriptorInsertRepository.java | 2 +- .../server/dao/sql/customer/CustomerRepository.java | 2 +- .../thingsboard/server/dao/sql/customer/JpaCustomerDao.java | 2 +- .../server/dao/sql/dashboard/DashboardInfoRepository.java | 2 +- .../server/dao/sql/dashboard/DashboardRepository.java | 2 +- .../thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java | 2 +- .../server/dao/sql/dashboard/JpaDashboardInfoDao.java | 2 +- .../server/dao/sql/device/DeviceCredentialsRepository.java | 2 +- .../thingsboard/server/dao/sql/device/DeviceRepository.java | 2 +- .../server/dao/sql/device/JpaDeviceCredentialsDao.java | 2 +- .../org/thingsboard/server/dao/sql/device/JpaDeviceDao.java | 2 +- .../server/dao/sql/entityview/EntityViewRepository.java | 2 +- .../server/dao/sql/entityview/JpaEntityViewDao.java | 2 +- .../server/dao/sql/event/AbstractEventInsertRepository.java | 2 +- .../server/dao/sql/event/EventInsertRepository.java | 2 +- .../org/thingsboard/server/dao/sql/event/EventRepository.java | 2 +- .../server/dao/sql/event/HsqlEventInsertRepository.java | 2 +- .../org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java | 2 +- .../server/dao/sql/event/PsqlEventInsertRepository.java | 2 +- .../thingsboard/server/dao/sql/relation/JpaRelationDao.java | 2 +- .../server/dao/sql/relation/RelationRepository.java | 2 +- .../org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java | 2 +- .../org/thingsboard/server/dao/sql/rule/JpaRuleNodeDao.java | 2 +- .../thingsboard/server/dao/sql/rule/RuleChainRepository.java | 2 +- .../thingsboard/server/dao/sql/rule/RuleNodeRepository.java | 2 +- .../server/dao/sql/settings/AdminSettingsRepository.java | 2 +- .../server/dao/sql/settings/JpaAdminSettingsDao.java | 2 +- .../org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java | 2 +- .../thingsboard/server/dao/sql/tenant/TenantRepository.java | 2 +- .../thingsboard/server/dao/sql/user/JpaUserCredentialsDao.java | 2 +- .../java/org/thingsboard/server/dao/sql/user/JpaUserDao.java | 2 +- .../server/dao/sql/user/UserCredentialsRepository.java | 2 +- .../org/thingsboard/server/dao/sql/user/UserRepository.java | 2 +- .../thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java | 2 +- .../thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java | 2 +- .../server/dao/sql/widget/WidgetTypeRepository.java | 2 +- .../server/dao/sql/widget/WidgetsBundleRepository.java | 2 +- .../thingsboard/server/dao/sqlts/AbstractInsertRepository.java | 2 +- .../server/dao/sqlts/AbstractLatestInsertRepository.java | 2 +- .../thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java | 2 +- .../server/dao/sqlts/AbstractTimeseriesInsertRepository.java | 2 +- .../server/dao/sqlts/timescale/AggregationRepository.java | 2 +- .../server/dao/sqlts/timescale/TimescaleInsertRepository.java | 2 +- .../server/dao/sqlts/timescale/TimescaleTimeseriesDao.java | 2 +- .../server/dao/sqlts/timescale/TsKvTimescaleRepository.java | 2 +- .../server/dao/sqlts/ts/HsqlLatestInsertRepository.java | 2 +- .../server/dao/sqlts/ts/HsqlTimeseriesInsertRepository.java | 2 +- .../org/thingsboard/server/dao/sqlts/ts/JpaTimeseriesDao.java | 2 +- .../server/dao/sqlts/ts/PsqlLatestInsertRepository.java | 2 +- .../server/dao/sqlts/ts/PsqlTimeseriesInsertRepository.java | 2 +- .../thingsboard/server/dao/sqlts/ts/TsKvLatestRepository.java | 2 +- .../org/thingsboard/server/dao/sqlts/ts/TsKvRepository.java | 2 +- .../org/thingsboard/server/dao/tenant/CassandraTenantDao.java | 2 +- .../main/java/org/thingsboard/server/dao/tenant/TenantDao.java | 2 +- .../org/thingsboard/server/dao/tenant/TenantServiceImpl.java | 2 +- .../server/dao/timeseries/AggregatePartitionsFunction.java | 2 +- .../server/dao/timeseries/BaseTimeseriesService.java | 2 +- .../server/dao/timeseries/CassandraBaseTimeseriesDao.java | 2 +- .../org/thingsboard/server/dao/timeseries/QueryCursor.java | 2 +- .../server/dao/timeseries/SimpleListenableFuture.java | 2 +- .../org/thingsboard/server/dao/timeseries/TimeseriesDao.java | 2 +- .../server/dao/timeseries/TsInsertExecutorType.java | 2 +- .../org/thingsboard/server/dao/timeseries/TsKvQueryCursor.java | 2 +- .../org/thingsboard/server/dao/timeseries/TsPartitionDate.java | 2 +- .../server/dao/user/CassandraUserCredentialsDao.java | 2 +- .../java/org/thingsboard/server/dao/user/CassandraUserDao.java | 2 +- .../org/thingsboard/server/dao/user/UserCredentialsDao.java | 2 +- dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java | 2 +- .../java/org/thingsboard/server/dao/user/UserServiceImpl.java | 2 +- .../server/dao/util/AbstractBufferedRateExecutor.java | 2 +- .../java/org/thingsboard/server/dao/util/AsyncRateLimiter.java | 2 +- .../java/org/thingsboard/server/dao/util/AsyncTaskContext.java | 2 +- .../org/thingsboard/server/dao/util/BufferedRateExecutor.java | 2 +- .../thingsboard/server/dao/util/TenantRateLimitException.java | 2 +- .../java/org/thingsboard/server/dao/util/TimescaleDBTsDao.java | 2 +- .../server/dao/util/mapping/AbstractJsonSqlTypeDescriptor.java | 2 +- .../org/thingsboard/server/dao/util/mapping/JacksonUtil.java | 2 +- .../server/dao/util/mapping/JsonStringSqlTypeDescriptor.java | 2 +- .../thingsboard/server/dao/util/mapping/JsonStringType.java | 2 +- .../server/dao/util/mapping/JsonTypeDescriptor.java | 2 +- .../thingsboard/server/dao/widget/CassandraWidgetTypeDao.java | 2 +- .../server/dao/widget/CassandraWidgetsBundleDao.java | 2 +- .../java/org/thingsboard/server/dao/widget/WidgetTypeDao.java | 2 +- .../thingsboard/server/dao/widget/WidgetTypeServiceImpl.java | 2 +- .../org/thingsboard/server/dao/widget/WidgetsBundleDao.java | 2 +- .../server/dao/widget/WidgetsBundleServiceImpl.java | 2 +- dao/src/main/resources/cassandra/schema-entities.cql | 2 +- dao/src/main/resources/cassandra/schema-ts.cql | 2 +- dao/src/main/resources/cassandra/system-data.cql | 2 +- dao/src/main/resources/sql/schema-entities-idx.sql | 2 +- dao/src/main/resources/sql/schema-entities.sql | 2 +- dao/src/main/resources/sql/schema-timescale-idx.sql | 2 +- dao/src/main/resources/sql/schema-timescale.sql | 2 +- dao/src/main/resources/sql/schema-ts.sql | 2 +- dao/src/main/resources/sql/system-data.sql | 2 +- .../java/org/thingsboard/server/dao/AbstractJpaDaoTest.java | 2 +- .../org/thingsboard/server/dao/CustomCassandraCQLUnit.java | 2 +- .../test/java/org/thingsboard/server/dao/CustomSqlUnit.java | 2 +- .../test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java | 2 +- .../java/org/thingsboard/server/dao/JpaDbunitTestConfig.java | 2 +- .../org/thingsboard/server/dao/NoSqlDaoServiceTestSuite.java | 2 +- .../org/thingsboard/server/dao/SqlDaoServiceTestSuite.java | 2 +- .../server/dao/nosql/RateLimitedResultSetFutureTest.java | 2 +- .../thingsboard/server/dao/service/AbstractServiceTest.java | 2 +- .../server/dao/service/BaseAdminSettingsServiceTest.java | 2 +- .../thingsboard/server/dao/service/BaseAlarmServiceTest.java | 2 +- .../thingsboard/server/dao/service/BaseAssetServiceTest.java | 2 +- .../server/dao/service/BaseCustomerServiceTest.java | 2 +- .../server/dao/service/BaseDashboardServiceTest.java | 2 +- .../server/dao/service/BaseDeviceCredentialsCacheTest.java | 2 +- .../server/dao/service/BaseDeviceCredentialsServiceTest.java | 2 +- .../thingsboard/server/dao/service/BaseDeviceServiceTest.java | 2 +- .../thingsboard/server/dao/service/BaseRelationCacheTest.java | 2 +- .../server/dao/service/BaseRelationServiceTest.java | 2 +- .../server/dao/service/BaseRuleChainServiceTest.java | 2 +- .../thingsboard/server/dao/service/BaseTenantServiceTest.java | 2 +- .../thingsboard/server/dao/service/BaseUserServiceTest.java | 2 +- .../server/dao/service/BaseWidgetTypeServiceTest.java | 2 +- .../server/dao/service/BaseWidgetsBundleServiceTest.java | 2 +- .../java/org/thingsboard/server/dao/service/DaoNoSqlTest.java | 2 +- .../java/org/thingsboard/server/dao/service/DaoSqlTest.java | 2 +- .../dao/service/attributes/BaseAttributesServiceTest.java | 2 +- .../service/attributes/nosql/AttributesServiceNoSqlTest.java | 2 +- .../dao/service/attributes/sql/AttributesServiceSqlTest.java | 2 +- .../server/dao/service/event/BaseEventServiceTest.java | 2 +- .../server/dao/service/event/nosql/EventServiceNoSqlTest.java | 2 +- .../server/dao/service/event/sql/EventServiceSqlTest.java | 2 +- .../dao/service/nosql/AdminSettingsServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/AlarmServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/AssetServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/CustomerServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/DashboardServiceNoSqlTest.java | 2 +- .../service/nosql/DeviceCredentialCacheServiceNoSqlTest.java | 2 +- .../dao/service/nosql/DeviceCredentialServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/DeviceServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/RelationCacheNoSqlTest.java | 2 +- .../server/dao/service/nosql/RelationServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/RuleChainServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/TenantServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/UserServiceNoSqlTest.java | 2 +- .../server/dao/service/nosql/WidgetTypeServiceNoSqlTest.java | 2 +- .../dao/service/nosql/WidgetsBundleServiceNoSqlTest.java | 2 +- .../server/dao/service/sql/AdminSettingsServiceSqlTest.java | 2 +- .../server/dao/service/sql/AlarmServiceSqlTest.java | 2 +- .../server/dao/service/sql/AssetServiceSqlTest.java | 2 +- .../server/dao/service/sql/CustomerServiceSqlTest.java | 2 +- .../server/dao/service/sql/DashboardServiceSqlTest.java | 2 +- .../dao/service/sql/DeviceCredentialsCacheServiceSqlTest.java | 2 +- .../dao/service/sql/DeviceCredentialsServiceSqlTest.java | 2 +- .../server/dao/service/sql/DeviceServiceSqlTest.java | 2 +- .../server/dao/service/sql/RelationCacheSqlTest.java | 2 +- .../server/dao/service/sql/RelationServiceSqlTest.java | 2 +- .../server/dao/service/sql/RuleChainServiceSqlTest.java | 2 +- .../server/dao/service/sql/TenantServiceSqlTest.java | 2 +- .../thingsboard/server/dao/service/sql/UserServiceSqlTest.java | 2 +- .../server/dao/service/sql/WidgetTypeServiceSqlTest.java | 2 +- .../server/dao/service/sql/WidgetsBundleServiceSqlTest.java | 2 +- .../dao/service/timeseries/BaseTimeseriesServiceTest.java | 2 +- .../service/timeseries/nosql/TimeseriesServiceNoSqlTest.java | 2 +- .../dao/service/timeseries/sql/TimeseriesServiceSqlTest.java | 2 +- .../org/thingsboard/server/dao/sql/alarm/JpaAlarmDaoTest.java | 2 +- .../org/thingsboard/server/dao/sql/asset/JpaAssetDaoTest.java | 2 +- .../thingsboard/server/dao/sql/audit/JpaAuditLogDaoTest.java | 2 +- .../dao/sql/component/JpaBaseComponentDescriptorDaoTest.java | 2 +- .../server/dao/sql/customer/JpaCustomerDaoTest.java | 2 +- .../server/dao/sql/dashboard/JpaDashboardInfoDaoTest.java | 2 +- .../server/dao/sql/device/JpaDeviceCredentialsDaoTest.java | 2 +- .../thingsboard/server/dao/sql/device/JpaDeviceDaoTest.java | 2 +- .../thingsboard/server/dao/sql/event/JpaBaseEventDaoTest.java | 2 +- .../thingsboard/server/dao/sql/tenant/JpaTenantDaoTest.java | 2 +- .../server/dao/sql/user/JpaUserCredentialsDaoTest.java | 2 +- .../org/thingsboard/server/dao/sql/user/JpaUserDaoTest.java | 2 +- .../server/dao/sql/widget/JpaWidgetTypeDaoTest.java | 2 +- .../server/dao/sql/widget/JpaWidgetsBundleDaoTest.java | 2 +- docker/compose-utils.sh | 2 +- docker/docker-compose.cassandra.yml | 2 +- docker/docker-compose.postgres.volumes.yml | 2 +- docker/docker-compose.postgres.yml | 2 +- docker/docker-compose.yml | 2 +- docker/docker-install-tb.sh | 2 +- docker/docker-remove-services.sh | 2 +- docker/docker-start-services.sh | 2 +- docker/docker-stop-services.sh | 2 +- docker/docker-update-service.sh | 2 +- docker/docker-upgrade-tb.sh | 2 +- docker/tb-transports/coap/conf/logback.xml | 2 +- docker/tb-transports/coap/conf/tb-coap-transport.conf | 2 +- docker/tb-transports/http/conf/logback.xml | 2 +- docker/tb-transports/http/conf/tb-http-transport.conf | 2 +- docker/tb-transports/mqtt/conf/logback.xml | 2 +- docker/tb-transports/mqtt/conf/tb-mqtt-transport.conf | 2 +- k8s/cassandra.yml | 2 +- k8s/database-setup.yml | 2 +- k8s/k8s-delete-all.sh | 2 +- k8s/k8s-delete-resources.sh | 2 +- k8s/k8s-deploy-resources.sh | 2 +- k8s/k8s-install-tb.sh | 2 +- k8s/k8s-upgrade-tb.sh | 2 +- k8s/postgres.yml | 2 +- k8s/tb-coap-transport-configmap.yml | 2 +- k8s/tb-http-transport-configmap.yml | 2 +- k8s/tb-mqtt-transport-configmap.yml | 2 +- k8s/tb-namespace.yml | 2 +- k8s/tb-node-cassandra-configmap.yml | 2 +- k8s/tb-node-configmap.yml | 2 +- k8s/tb-node-postgres-configmap.yml | 2 +- k8s/thingsboard.yml | 2 +- license-header-template.txt | 2 +- msa/black-box-tests/pom.xml | 2 +- .../java/org/thingsboard/server/msa/AbstractContainerTest.java | 2 +- .../java/org/thingsboard/server/msa/ContainerTestSuite.java | 2 +- .../java/org/thingsboard/server/msa/DockerComposeExecutor.java | 2 +- .../org/thingsboard/server/msa/ThingsBoardDbInstaller.java | 2 +- .../src/test/java/org/thingsboard/server/msa/WsClient.java | 2 +- .../thingsboard/server/msa/connectivity/HttpClientTest.java | 2 +- .../thingsboard/server/msa/connectivity/MqttClientTest.java | 2 +- .../org/thingsboard/server/msa/mapper/AttributesResponse.java | 2 +- .../org/thingsboard/server/msa/mapper/WsTelemetryResponse.java | 2 +- msa/js-executor/api/jsExecutor.js | 2 +- msa/js-executor/api/jsInvokeMessageProcessor.js | 2 +- msa/js-executor/api/utils.js | 2 +- msa/js-executor/build.gradle | 2 +- msa/js-executor/config/custom-environment-variables.yml | 2 +- msa/js-executor/config/default.yml | 2 +- msa/js-executor/config/logger.js | 2 +- msa/js-executor/config/tb-js-executor.conf | 2 +- msa/js-executor/docker/Dockerfile | 2 +- msa/js-executor/docker/start-js-executor.sh | 2 +- msa/js-executor/install.js | 2 +- msa/js-executor/pom.xml | 2 +- msa/js-executor/server.js | 3 +-- msa/js-executor/src/main/assembly/windows.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/docker/Dockerfile | 2 +- msa/tb-node/docker/start-tb-node.sh | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/docker-cassandra/Dockerfile | 2 +- msa/tb/docker-cassandra/start-db.sh | 2 +- msa/tb/docker-cassandra/stop-db.sh | 2 +- msa/tb/docker-postgres/Dockerfile | 2 +- msa/tb/docker-postgres/start-db.sh | 2 +- msa/tb/docker-postgres/stop-db.sh | 2 +- msa/tb/docker-tb/Dockerfile | 2 +- msa/tb/docker-tb/start-db.sh | 2 +- msa/tb/docker-tb/stop-db.sh | 2 +- msa/tb/docker/install-tb.sh | 2 +- msa/tb/docker/logback.xml | 2 +- msa/tb/docker/start-tb.sh | 2 +- msa/tb/docker/thingsboard.conf | 2 +- msa/tb/docker/upgrade-tb.sh | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/docker/Dockerfile | 2 +- msa/transport/coap/docker/start-tb-coap-transport.sh | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/docker/Dockerfile | 2 +- msa/transport/http/docker/start-tb-http-transport.sh | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/mqtt/docker/Dockerfile | 2 +- msa/transport/mqtt/docker/start-tb-mqtt-transport.sh | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/web-ui/build.gradle | 2 +- msa/web-ui/config/custom-environment-variables.yml | 2 +- msa/web-ui/config/default.yml | 2 +- msa/web-ui/config/logger.js | 2 +- msa/web-ui/config/tb-web-ui.conf | 2 +- msa/web-ui/docker/Dockerfile | 2 +- msa/web-ui/docker/start-web-ui.sh | 2 +- msa/web-ui/install.js | 2 +- msa/web-ui/pom.xml | 2 +- msa/web-ui/server.js | 2 +- msa/web-ui/src/main/assembly/windows.xml | 2 +- netty-mqtt/pom.xml | 2 +- .../main/java/org/thingsboard/mqtt/ChannelClosedException.java | 2 +- .../src/main/java/org/thingsboard/mqtt/MqttChannelHandler.java | 2 +- netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClient.java | 2 +- .../src/main/java/org/thingsboard/mqtt/MqttClientCallback.java | 2 +- .../src/main/java/org/thingsboard/mqtt/MqttClientConfig.java | 2 +- .../src/main/java/org/thingsboard/mqtt/MqttClientImpl.java | 2 +- .../src/main/java/org/thingsboard/mqtt/MqttConnectResult.java | 2 +- netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttHandler.java | 2 +- .../java/org/thingsboard/mqtt/MqttIncomingQos2Publish.java | 2 +- .../src/main/java/org/thingsboard/mqtt/MqttLastWill.java | 2 +- .../src/main/java/org/thingsboard/mqtt/MqttPendingPublish.java | 2 +- .../java/org/thingsboard/mqtt/MqttPendingSubscription.java | 2 +- .../java/org/thingsboard/mqtt/MqttPendingUnsubscription.java | 2 +- .../src/main/java/org/thingsboard/mqtt/MqttPingHandler.java | 2 +- .../src/main/java/org/thingsboard/mqtt/MqttSubscription.java | 2 +- .../main/java/org/thingsboard/mqtt/RetransmissionHandler.java | 2 +- pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- .../thingsboard/rule/engine/api/EmptyNodeConfiguration.java | 2 +- .../main/java/org/thingsboard/rule/engine/api/MailService.java | 2 +- .../org/thingsboard/rule/engine/api/NodeConfiguration.java | 2 +- .../java/org/thingsboard/rule/engine/api/NodeDefinition.java | 2 +- .../main/java/org/thingsboard/rule/engine/api/RpcError.java | 2 +- .../rule/engine/api/RuleChainTransactionService.java | 2 +- .../rule/engine/api/RuleEngineDeviceRpcRequest.java | 2 +- .../rule/engine/api/RuleEngineDeviceRpcResponse.java | 2 +- .../org/thingsboard/rule/engine/api/RuleEngineRpcService.java | 2 +- .../rule/engine/api/RuleEngineTelemetryService.java | 2 +- .../main/java/org/thingsboard/rule/engine/api/RuleNode.java | 2 +- .../java/org/thingsboard/rule/engine/api/ScriptEngine.java | 2 +- .../main/java/org/thingsboard/rule/engine/api/TbContext.java | 2 +- .../src/main/java/org/thingsboard/rule/engine/api/TbNode.java | 2 +- .../org/thingsboard/rule/engine/api/TbNodeConfiguration.java | 2 +- .../java/org/thingsboard/rule/engine/api/TbNodeException.java | 2 +- .../main/java/org/thingsboard/rule/engine/api/TbNodeState.java | 2 +- .../java/org/thingsboard/rule/engine/api/TbRelationTypes.java | 2 +- .../org/thingsboard/rule/engine/api/msg/DeviceAttributes.java | 2 +- .../engine/api/msg/DeviceAttributesEventNotificationMsg.java | 2 +- .../engine/api/msg/DeviceCredentialsUpdateNotificationMsg.java | 2 +- .../org/thingsboard/rule/engine/api/msg/DeviceMetaData.java | 2 +- .../rule/engine/api/msg/DeviceNameOrTypeUpdateMsg.java | 2 +- .../rule/engine/api/msg/ToDeviceActorNotificationMsg.java | 2 +- .../java/org/thingsboard/rule/engine/api/util/TbNodeUtils.java | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- .../thingsboard/rule/engine/action/TbAbstractAlarmNode.java | 2 +- .../rule/engine/action/TbAbstractAlarmNodeConfiguration.java | 2 +- .../rule/engine/action/TbAbstractCustomerActionNode.java | 2 +- .../action/TbAbstractCustomerActionNodeConfiguration.java | 2 +- .../rule/engine/action/TbAbstractRelationActionNode.java | 2 +- .../action/TbAbstractRelationActionNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/action/TbAssignToCustomerNode.java | 2 +- .../engine/action/TbAssignToCustomerNodeConfiguration.java | 2 +- .../org/thingsboard/rule/engine/action/TbClearAlarmNode.java | 2 +- .../rule/engine/action/TbClearAlarmNodeConfiguration.java | 2 +- .../rule/engine/action/TbCopyAttributesToEntityViewNode.java | 2 +- .../org/thingsboard/rule/engine/action/TbCreateAlarmNode.java | 2 +- .../rule/engine/action/TbCreateAlarmNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/action/TbCreateRelationNode.java | 2 +- .../rule/engine/action/TbCreateRelationNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/action/TbDeleteRelationNode.java | 2 +- .../rule/engine/action/TbDeleteRelationNodeConfiguration.java | 2 +- .../java/org/thingsboard/rule/engine/action/TbLogNode.java | 2 +- .../thingsboard/rule/engine/action/TbLogNodeConfiguration.java | 2 +- .../org/thingsboard/rule/engine/action/TbMsgCountNode.java | 2 +- .../rule/engine/action/TbMsgCountNodeConfiguration.java | 2 +- .../rule/engine/action/TbSaveToCustomCassandraTableNode.java | 2 +- .../action/TbSaveToCustomCassandraTableNodeConfiguration.java | 2 +- .../rule/engine/action/TbUnassignFromCustomerNode.java | 2 +- .../engine/action/TbUnassignFromCustomerNodeConfiguration.java | 2 +- .../java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java | 2 +- .../rule/engine/aws/sns/TbSnsNodeConfiguration.java | 2 +- .../java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java | 2 +- .../rule/engine/aws/sqs/TbSqsNodeConfiguration.java | 2 +- .../org/thingsboard/rule/engine/data/DeviceRelationsQuery.java | 2 +- .../java/org/thingsboard/rule/engine/data/RelationsQuery.java | 2 +- .../org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java | 2 +- .../rule/engine/debug/TbMsgGeneratorNodeConfiguration.java | 2 +- .../java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java | 2 +- .../rule/engine/delay/TbMsgDelayNodeConfiguration.java | 2 +- .../org/thingsboard/rule/engine/filter/TbCheckMessageNode.java | 2 +- .../rule/engine/filter/TbCheckMessageNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/filter/TbCheckRelationNode.java | 2 +- .../rule/engine/filter/TbCheckRelationNodeConfiguration.java | 2 +- .../org/thingsboard/rule/engine/filter/TbJsFilterNode.java | 2 +- .../rule/engine/filter/TbJsFilterNodeConfiguration.java | 2 +- .../org/thingsboard/rule/engine/filter/TbJsSwitchNode.java | 2 +- .../rule/engine/filter/TbJsSwitchNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java | 2 +- .../rule/engine/filter/TbMsgTypeFilterNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java | 2 +- .../rule/engine/filter/TbOriginatorTypeFilterNode.java | 2 +- .../engine/filter/TbOriginatorTypeFilterNodeConfiguration.java | 2 +- .../rule/engine/filter/TbOriginatorTypeSwitchNode.java | 2 +- .../org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java | 2 +- .../rule/engine/gcp/pubsub/TbPubSubNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/geo/AbstractGeofencingNode.java | 2 +- .../main/java/org/thingsboard/rule/engine/geo/Coordinates.java | 2 +- .../org/thingsboard/rule/engine/geo/EntityGeofencingState.java | 2 +- .../src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java | 2 +- .../main/java/org/thingsboard/rule/engine/geo/Perimeter.java | 2 +- .../java/org/thingsboard/rule/engine/geo/PerimeterType.java | 2 +- .../main/java/org/thingsboard/rule/engine/geo/RangeUnit.java | 2 +- .../thingsboard/rule/engine/geo/TbGpsGeofencingActionNode.java | 2 +- .../engine/geo/TbGpsGeofencingActionNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java | 2 +- .../engine/geo/TbGpsGeofencingFilterNodeConfiguration.java | 2 +- .../java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java | 2 +- .../rule/engine/kafka/TbKafkaNodeConfiguration.java | 2 +- .../main/java/org/thingsboard/rule/engine/mail/EmailPojo.java | 2 +- .../org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java | 2 +- .../rule/engine/mail/TbMsgToEmailNodeConfiguration.java | 2 +- .../java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java | 2 +- .../rule/engine/mail/TbSendEmailNodeConfiguration.java | 2 +- .../rule/engine/metadata/TbAbstractGetAttributesNode.java | 2 +- .../rule/engine/metadata/TbAbstractGetEntityDetailsNode.java | 2 +- .../metadata/TbAbstractGetEntityDetailsNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java | 2 +- .../thingsboard/rule/engine/metadata/TbGetAttributesNode.java | 2 +- .../rule/engine/metadata/TbGetAttributesNodeConfiguration.java | 2 +- .../rule/engine/metadata/TbGetCustomerAttributeNode.java | 2 +- .../rule/engine/metadata/TbGetCustomerDetailsNode.java | 2 +- .../engine/metadata/TbGetCustomerDetailsNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java | 2 +- .../rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java | 2 +- .../rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java | 2 +- .../engine/metadata/TbGetOriginatorFieldsConfiguration.java | 2 +- .../rule/engine/metadata/TbGetOriginatorFieldsNode.java | 2 +- .../engine/metadata/TbGetRelatedAttrNodeConfiguration.java | 2 +- .../rule/engine/metadata/TbGetRelatedAttributeNode.java | 2 +- .../thingsboard/rule/engine/metadata/TbGetTelemetryNode.java | 2 +- .../rule/engine/metadata/TbGetTelemetryNodeConfiguration.java | 2 +- .../rule/engine/metadata/TbGetTenantAttributeNode.java | 2 +- .../rule/engine/metadata/TbGetTenantDetailsNode.java | 2 +- .../engine/metadata/TbGetTenantDetailsNodeConfiguration.java | 2 +- .../main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java | 2 +- .../thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java | 2 +- .../rule/engine/mqtt/credentials/AnonymousCredentials.java | 2 +- .../rule/engine/mqtt/credentials/BasicCredentials.java | 2 +- .../rule/engine/mqtt/credentials/CertPemClientCredentials.java | 2 +- .../rule/engine/mqtt/credentials/MqttClientCredentials.java | 2 +- .../org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java | 2 +- .../rule/engine/rabbitmq/TbRabbitMqNodeConfiguration.java | 2 +- .../java/org/thingsboard/rule/engine/rest/TbHttpClient.java | 2 +- .../thingsboard/rule/engine/rest/TbRedisQueueProcessor.java | 2 +- .../org/thingsboard/rule/engine/rest/TbRestApiCallNode.java | 2 +- .../rule/engine/rest/TbRestApiCallNodeConfiguration.java | 2 +- .../org/thingsboard/rule/engine/rpc/TbSendRPCReplyNode.java | 2 +- .../org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java | 2 +- .../rule/engine/rpc/TbSendRpcReplyNodeConfiguration.java | 2 +- .../rule/engine/rpc/TbSendRpcRequestNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java | 2 +- .../engine/telemetry/TbMsgAttributesNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java | 2 +- .../engine/telemetry/TbMsgTimeseriesNodeConfiguration.java | 2 +- .../rule/engine/telemetry/TelemetryNodeCallback.java | 2 +- .../rule/engine/transaction/TbSynchronizationBeginNode.java | 2 +- .../rule/engine/transaction/TbSynchronizationEndNode.java | 2 +- .../rule/engine/transform/TbAbstractTransformNode.java | 2 +- .../rule/engine/transform/TbChangeOriginatorNode.java | 2 +- .../engine/transform/TbChangeOriginatorNodeConfiguration.java | 2 +- .../thingsboard/rule/engine/transform/TbTransformMsgNode.java | 2 +- .../rule/engine/transform/TbTransformMsgNodeConfiguration.java | 2 +- .../rule/engine/transform/TbTransformNodeConfiguration.java | 2 +- .../rule/engine/util/EntitiesAlarmOriginatorIdAsyncLoader.java | 2 +- .../rule/engine/util/EntitiesCustomerIdAsyncLoader.java | 2 +- .../rule/engine/util/EntitiesFieldsAsyncLoader.java | 2 +- .../rule/engine/util/EntitiesRelatedDeviceIdAsyncLoader.java | 2 +- .../rule/engine/util/EntitiesRelatedEntityIdAsyncLoader.java | 2 +- .../rule/engine/util/EntitiesTenantIdAsyncLoader.java | 2 +- .../java/org/thingsboard/rule/engine/util/EntityContainer.java | 2 +- .../java/org/thingsboard/rule/engine/util/EntityDetails.java | 2 +- .../org/thingsboard/rule/engine/action/TbAlarmNodeTest.java | 2 +- .../org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java | 2 +- .../org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java | 2 +- .../org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java | 2 +- .../rule/engine/metadata/TbGetCustomerAttributeNodeTest.java | 2 +- .../rule/engine/transform/TbChangeOriginatorNodeTest.java | 2 +- .../rule/engine/transform/TbTransformMsgNodeTest.java | 2 +- tools/pom.xml | 2 +- .../main/java/org/thingsboard/client/tools/MqttSslClient.java | 2 +- .../src/main/java/org/thingsboard/client/tools/RestClient.java | 2 +- .../org/thingsboard/client/tools/migrator/MigratorTool.java | 2 +- .../thingsboard/client/tools/migrator/PgCaLatestMigrator.java | 2 +- .../tools/migrator/PostgresToCassandraTelemetryMigrator.java | 2 +- .../org/thingsboard/client/tools/migrator/WriterBuilder.java | 2 +- tools/src/main/python/mqtt-send-telemetry.py | 2 +- tools/src/main/python/one-way-ssl-mqtt-client.py | 2 +- tools/src/main/python/simple-mqtt-client.py | 2 +- tools/src/main/python/two-way-ssl-mqtt-client.py | 2 +- tools/src/main/shell/client.keygen.sh | 2 +- tools/src/main/shell/server.keygen.sh | 2 +- transport/coap/build.gradle | 2 +- transport/coap/pom.xml | 2 +- transport/coap/src/main/assembly/windows.xml | 2 +- transport/coap/src/main/conf/logback.xml | 2 +- transport/coap/src/main/conf/tb-coap-transport.conf | 2 +- .../server/coap/ThingsboardCoapTransportApplication.java | 2 +- transport/coap/src/main/resources/logback.xml | 2 +- transport/coap/src/main/resources/tb-coap-transport.yml | 2 +- transport/http/build.gradle | 2 +- transport/http/pom.xml | 2 +- transport/http/src/main/assembly/windows.xml | 2 +- transport/http/src/main/conf/logback.xml | 2 +- transport/http/src/main/conf/tb-http-transport.conf | 2 +- .../server/http/ThingsboardHttpTransportApplication.java | 2 +- transport/http/src/main/resources/logback.xml | 2 +- transport/http/src/main/resources/tb-http-transport.yml | 2 +- transport/mqtt/build.gradle | 2 +- transport/mqtt/pom.xml | 2 +- transport/mqtt/src/main/assembly/windows.xml | 2 +- transport/mqtt/src/main/conf/logback.xml | 2 +- transport/mqtt/src/main/conf/tb-mqtt-transport.conf | 2 +- .../server/mqtt/ThingsboardMqttTransportApplication.java | 2 +- transport/mqtt/src/main/resources/logback.xml | 2 +- transport/mqtt/src/main/resources/tb-mqtt-transport.yml | 2 +- transport/pom.xml | 2 +- ui/pom.xml | 2 +- ui/server.js | 2 +- ui/src/app/admin/admin.controller.js | 3 +-- ui/src/app/admin/admin.routes.js | 2 +- ui/src/app/admin/general-settings.tpl.html | 2 +- ui/src/app/admin/index.js | 2 +- ui/src/app/admin/outgoing-mail-settings.tpl.html | 2 +- ui/src/app/admin/security-settings.controller.js | 3 +-- ui/src/app/admin/security-settings.tpl.html | 2 +- ui/src/app/admin/settings-card.scss | 3 +-- ui/src/app/alarm/alarm-details-dialog.controller.js | 2 +- ui/src/app/alarm/alarm-details-dialog.scss | 2 +- ui/src/app/alarm/alarm-details-dialog.tpl.html | 2 +- ui/src/app/alarm/alarm-header.directive.js | 2 +- ui/src/app/alarm/alarm-header.tpl.html | 2 +- ui/src/app/alarm/alarm-row.directive.js | 2 +- ui/src/app/alarm/alarm-row.tpl.html | 2 +- ui/src/app/alarm/alarm-table.directive.js | 2 +- ui/src/app/alarm/alarm-table.tpl.html | 2 +- ui/src/app/alarm/alarm.scss | 2 +- ui/src/app/alarm/index.js | 2 +- ui/src/app/api/admin.service.js | 2 +- ui/src/app/api/alarm.service.js | 2 +- ui/src/app/api/alias-controller.js | 2 +- ui/src/app/api/asset.service.js | 2 +- ui/src/app/api/attribute.service.js | 2 +- ui/src/app/api/audit-log.service.js | 2 +- ui/src/app/api/component-descriptor.service.js | 2 +- ui/src/app/api/customer.service.js | 2 +- ui/src/app/api/dashboard.service.js | 2 +- ui/src/app/api/data-aggregator.js | 2 +- ui/src/app/api/datasource.service.js | 2 +- ui/src/app/api/device.service.js | 2 +- ui/src/app/api/entity-relation.service.js | 2 +- ui/src/app/api/entity-view.service.js | 2 +- ui/src/app/api/entity.service.js | 2 +- ui/src/app/api/event.service.js | 2 +- ui/src/app/api/login.service.js | 2 +- ui/src/app/api/rule-chain.service.js | 2 +- ui/src/app/api/subscription.js | 2 +- ui/src/app/api/telemetry-websocket.service.js | 2 +- ui/src/app/api/tenant.service.js | 2 +- ui/src/app/api/time.service.js | 2 +- ui/src/app/api/user.service.js | 2 +- ui/src/app/api/widget.service.js | 2 +- ui/src/app/app.config.js | 2 +- ui/src/app/app.js | 2 +- ui/src/app/app.run.js | 2 +- ui/src/app/asset/add-asset.tpl.html | 2 +- ui/src/app/asset/add-assets-to-customer.controller.js | 2 +- ui/src/app/asset/add-assets-to-customer.tpl.html | 2 +- ui/src/app/asset/asset-card.tpl.html | 2 +- ui/src/app/asset/asset-fieldset.tpl.html | 2 +- ui/src/app/asset/asset.controller.js | 2 +- ui/src/app/asset/asset.directive.js | 2 +- ui/src/app/asset/asset.routes.js | 2 +- ui/src/app/asset/assets.tpl.html | 2 +- ui/src/app/asset/assign-to-customer.controller.js | 2 +- ui/src/app/asset/assign-to-customer.tpl.html | 2 +- ui/src/app/asset/index.js | 2 +- ui/src/app/audit/audit-log-details-dialog.controller.js | 2 +- ui/src/app/audit/audit-log-details-dialog.scss | 2 +- ui/src/app/audit/audit-log-details-dialog.tpl.html | 2 +- ui/src/app/audit/audit-log-header.directive.js | 2 +- ui/src/app/audit/audit-log-header.tpl.html | 2 +- ui/src/app/audit/audit-log-row.directive.js | 2 +- ui/src/app/audit/audit-log-row.tpl.html | 2 +- ui/src/app/audit/audit-log-table.directive.js | 2 +- ui/src/app/audit/audit-log-table.tpl.html | 2 +- ui/src/app/audit/audit-log.routes.js | 2 +- ui/src/app/audit/audit-log.scss | 2 +- ui/src/app/audit/audit-logs.controller.js | 2 +- ui/src/app/audit/audit-logs.tpl.html | 2 +- ui/src/app/audit/index.js | 2 +- ui/src/app/common/dashboard-utils.service.js | 2 +- ui/src/app/common/raf.provider.js | 2 +- ui/src/app/common/thirdparty-fix.js | 2 +- ui/src/app/common/types.constant.js | 2 +- ui/src/app/common/utf8-support.js | 2 +- ui/src/app/common/utils.service.js | 2 +- ui/src/app/components/ace-editor-fix.js | 2 +- ui/src/app/components/circular-progress.directive.js | 2 +- ui/src/app/components/confirm-on-exit.directive.js | 2 +- ui/src/app/components/contact-short.filter.js | 2 +- ui/src/app/components/contact.directive.js | 2 +- ui/src/app/components/contact.tpl.html | 2 +- ui/src/app/components/dashboard-autocomplete.directive.js | 2 +- ui/src/app/components/dashboard-autocomplete.scss | 2 +- ui/src/app/components/dashboard-autocomplete.tpl.html | 2 +- ui/src/app/components/dashboard-select-panel.controller.js | 2 +- ui/src/app/components/dashboard-select-panel.tpl.html | 2 +- ui/src/app/components/dashboard-select.directive.js | 2 +- ui/src/app/components/dashboard-select.scss | 2 +- ui/src/app/components/dashboard-select.tpl.html | 2 +- ui/src/app/components/dashboard.directive.js | 2 +- ui/src/app/components/dashboard.scss | 2 +- ui/src/app/components/dashboard.tpl.html | 2 +- ui/src/app/components/datakey-config-dialog.controller.js | 2 +- ui/src/app/components/datakey-config-dialog.tpl.html | 2 +- ui/src/app/components/datakey-config.directive.js | 2 +- ui/src/app/components/datakey-config.scss | 2 +- ui/src/app/components/datakey-config.tpl.html | 2 +- ui/src/app/components/datasource-entity.directive.js | 2 +- ui/src/app/components/datasource-entity.scss | 2 +- ui/src/app/components/datasource-entity.tpl.html | 2 +- ui/src/app/components/datasource-func.directive.js | 2 +- ui/src/app/components/datasource-func.scss | 2 +- ui/src/app/components/datasource-func.tpl.html | 2 +- ui/src/app/components/datasource.directive.js | 2 +- ui/src/app/components/datasource.scss | 2 +- ui/src/app/components/datasource.tpl.html | 2 +- ui/src/app/components/datetime-period.directive.js | 2 +- ui/src/app/components/datetime-period.scss | 2 +- ui/src/app/components/datetime-period.tpl.html | 2 +- ui/src/app/components/details-sidenav.directive.js | 2 +- ui/src/app/components/details-sidenav.scss | 2 +- ui/src/app/components/details-sidenav.tpl.html | 2 +- ui/src/app/components/entity-alias-select.directive.js | 2 +- ui/src/app/components/entity-alias-select.scss | 2 +- ui/src/app/components/entity-alias-select.tpl.html | 2 +- ui/src/app/components/expand-fullscreen.directive.js | 2 +- ui/src/app/components/expand-fullscreen.scss | 2 +- ui/src/app/components/finish-render.directive.js | 2 +- ui/src/app/components/grid.directive.js | 2 +- ui/src/app/components/grid.scss | 2 +- ui/src/app/components/grid.tpl.html | 2 +- ui/src/app/components/js-func.directive.js | 2 +- ui/src/app/components/js-func.scss | 2 +- ui/src/app/components/js-func.tpl.html | 2 +- ui/src/app/components/json-content.directive.js | 2 +- ui/src/app/components/json-content.scss | 2 +- ui/src/app/components/json-content.tpl.html | 2 +- ui/src/app/components/json-form.directive.js | 2 +- ui/src/app/components/json-form.scss | 2 +- ui/src/app/components/json-form.tpl.html | 2 +- ui/src/app/components/json-object-edit.directive.js | 2 +- ui/src/app/components/json-object-edit.scss | 2 +- ui/src/app/components/json-object-edit.tpl.html | 2 +- ui/src/app/components/keyboard-shortcut.filter.js | 2 +- ui/src/app/components/kv-map.directive.js | 2 +- ui/src/app/components/kv-map.scss | 2 +- ui/src/app/components/kv-map.tpl.html | 2 +- ui/src/app/components/led-light.directive.js | 2 +- ui/src/app/components/legend-config-button.tpl.html | 2 +- ui/src/app/components/legend-config-panel.controller.js | 2 +- ui/src/app/components/legend-config-panel.tpl.html | 2 +- ui/src/app/components/legend-config.directive.js | 2 +- ui/src/app/components/legend-config.scss | 2 +- ui/src/app/components/legend.directive.js | 2 +- ui/src/app/components/legend.scss | 2 +- ui/src/app/components/legend.tpl.html | 2 +- ui/src/app/components/material-icon-select.directive.js | 2 +- ui/src/app/components/material-icon-select.scss | 2 +- ui/src/app/components/material-icon-select.tpl.html | 2 +- ui/src/app/components/material-icons-dialog.controller.js | 2 +- ui/src/app/components/material-icons-dialog.scss | 2 +- ui/src/app/components/material-icons-dialog.tpl.html | 2 +- ui/src/app/components/md-chip-draggable.directive.js | 3 +-- ui/src/app/components/md-chip-draggable.scss | 2 +- ui/src/app/components/menu-link.directive.js | 2 +- ui/src/app/components/menu-link.scss | 2 +- ui/src/app/components/menu-link.tpl.html | 2 +- ui/src/app/components/menu-toggle.tpl.html | 2 +- ui/src/app/components/mousepoint-menu.directive.js | 2 +- ui/src/app/components/nav-tree.directive.js | 2 +- ui/src/app/components/nav-tree.scss | 2 +- ui/src/app/components/nav-tree.tpl.html | 2 +- ui/src/app/components/no-animate.directive.js | 2 +- ui/src/app/components/react/json-form-ace-editor.jsx | 2 +- ui/src/app/components/react/json-form-ace-editor.scss | 3 +-- ui/src/app/components/react/json-form-array.jsx | 2 +- ui/src/app/components/react/json-form-base-component.jsx | 2 +- ui/src/app/components/react/json-form-checkbox.jsx | 2 +- ui/src/app/components/react/json-form-color.jsx | 2 +- ui/src/app/components/react/json-form-color.scss | 2 +- ui/src/app/components/react/json-form-css.jsx | 2 +- ui/src/app/components/react/json-form-date.jsx | 2 +- ui/src/app/components/react/json-form-fieldset.jsx | 2 +- ui/src/app/components/react/json-form-html.jsx | 2 +- ui/src/app/components/react/json-form-icon.jsx | 2 +- ui/src/app/components/react/json-form-image.jsx | 2 +- ui/src/app/components/react/json-form-image.scss | 2 +- ui/src/app/components/react/json-form-javascript.jsx | 2 +- ui/src/app/components/react/json-form-json.jsx | 2 +- ui/src/app/components/react/json-form-number.jsx | 2 +- ui/src/app/components/react/json-form-rc-select.jsx | 2 +- ui/src/app/components/react/json-form-react.jsx | 2 +- ui/src/app/components/react/json-form-schema-form.jsx | 2 +- ui/src/app/components/react/json-form-text.jsx | 2 +- ui/src/app/components/react/json-form.scss | 2 +- ui/src/app/components/react/styles/thingsboardTheme.js | 2 +- ui/src/app/components/related-entity-autocomplete.directive.js | 2 +- ui/src/app/components/related-entity-autocomplete.scss | 2 +- ui/src/app/components/related-entity-autocomplete.tpl.html | 2 +- ui/src/app/components/scope-element.directive.js | 2 +- ui/src/app/components/side-menu.directive.js | 2 +- ui/src/app/components/side-menu.scss | 2 +- ui/src/app/components/side-menu.tpl.html | 2 +- ui/src/app/components/socialshare-panel.directive.js | 2 +- ui/src/app/components/socialshare-panel.tpl.html | 2 +- ui/src/app/components/tb-event-directives.js | 2 +- ui/src/app/components/timeinterval.directive.js | 2 +- ui/src/app/components/timeinterval.scss | 2 +- ui/src/app/components/timeinterval.tpl.html | 2 +- ui/src/app/components/timewindow-button.tpl.html | 2 +- ui/src/app/components/timewindow-panel.controller.js | 2 +- ui/src/app/components/timewindow-panel.tpl.html | 2 +- ui/src/app/components/timewindow.directive.js | 2 +- ui/src/app/components/timewindow.scss | 2 +- ui/src/app/components/timewindow.tpl.html | 2 +- ui/src/app/components/truncate.filter.js | 2 +- .../widget/action/custom-action-pretty-editor.directive.js | 2 +- .../components/widget/action/custom-action-pretty-editor.scss | 2 +- .../widget/action/custom-action-pretty-editor.tpl.html | 2 +- .../widget/action/manage-widget-actions.directive.js | 2 +- ui/src/app/components/widget/action/manage-widget-actions.scss | 2 +- .../components/widget/action/manage-widget-actions.tpl.html | 2 +- .../widget/action/widget-action-dialog.controller.js | 2 +- .../app/components/widget/action/widget-action-dialog.tpl.html | 2 +- ui/src/app/components/widget/widget-config.directive.js | 2 +- ui/src/app/components/widget/widget-config.scss | 2 +- ui/src/app/components/widget/widget-config.tpl.html | 2 +- ui/src/app/components/widget/widget.controller.js | 2 +- ui/src/app/components/widget/widget.directive.js | 2 +- ui/src/app/components/widget/widget.scss | 2 +- ui/src/app/components/widgets-bundle-select.directive.js | 2 +- ui/src/app/components/widgets-bundle-select.scss | 2 +- ui/src/app/components/widgets-bundle-select.tpl.html | 2 +- ui/src/app/customer/add-customer.tpl.html | 2 +- ui/src/app/customer/customer-card.tpl.html | 2 +- ui/src/app/customer/customer-fieldset.tpl.html | 2 +- ui/src/app/customer/customer.controller.js | 2 +- ui/src/app/customer/customer.directive.js | 2 +- ui/src/app/customer/customer.routes.js | 2 +- ui/src/app/customer/customers.tpl.html | 2 +- ui/src/app/customer/index.js | 2 +- ui/src/app/dashboard/add-dashboard.tpl.html | 2 +- ui/src/app/dashboard/add-dashboards-to-customer.controller.js | 2 +- ui/src/app/dashboard/add-dashboards-to-customer.tpl.html | 2 +- ui/src/app/dashboard/add-widget.controller.js | 2 +- ui/src/app/dashboard/add-widget.tpl.html | 2 +- ui/src/app/dashboard/dashboard-card.scss | 2 +- ui/src/app/dashboard/dashboard-card.tpl.html | 2 +- ui/src/app/dashboard/dashboard-fieldset.tpl.html | 2 +- ui/src/app/dashboard/dashboard-settings.controller.js | 2 +- ui/src/app/dashboard/dashboard-settings.scss | 2 +- ui/src/app/dashboard/dashboard-settings.tpl.html | 2 +- ui/src/app/dashboard/dashboard-toolbar.directive.js | 2 +- ui/src/app/dashboard/dashboard-toolbar.scss | 2 +- ui/src/app/dashboard/dashboard-toolbar.tpl.html | 2 +- ui/src/app/dashboard/dashboard.controller.js | 2 +- ui/src/app/dashboard/dashboard.directive.js | 2 +- ui/src/app/dashboard/dashboard.routes.js | 2 +- ui/src/app/dashboard/dashboard.scss | 2 +- ui/src/app/dashboard/dashboard.tpl.html | 2 +- ui/src/app/dashboard/dashboards.controller.js | 2 +- ui/src/app/dashboard/dashboards.tpl.html | 2 +- ui/src/app/dashboard/edit-widget.directive.js | 2 +- ui/src/app/dashboard/edit-widget.tpl.html | 2 +- ui/src/app/dashboard/index.js | 2 +- ui/src/app/dashboard/layouts/dashboard-layout.directive.js | 2 +- ui/src/app/dashboard/layouts/dashboard-layout.tpl.html | 2 +- ui/src/app/dashboard/layouts/index.js | 2 +- .../dashboard/layouts/manage-dashboard-layouts.controller.js | 2 +- ui/src/app/dashboard/layouts/manage-dashboard-layouts.tpl.html | 2 +- .../app/dashboard/layouts/select-target-layout.controller.js | 2 +- ui/src/app/dashboard/layouts/select-target-layout.tpl.html | 2 +- ui/src/app/dashboard/make-dashboard-public-dialog.tpl.html | 2 +- ui/src/app/dashboard/manage-assigned-customers.controller.js | 2 +- ui/src/app/dashboard/manage-assigned-customers.tpl.html | 2 +- .../app/dashboard/states/dashboard-state-dialog.controller.js | 2 +- ui/src/app/dashboard/states/dashboard-state-dialog.tpl.html | 2 +- ui/src/app/dashboard/states/default-state-controller.js | 2 +- ui/src/app/dashboard/states/default-state-controller.scss | 2 +- ui/src/app/dashboard/states/default-state-controller.tpl.html | 2 +- ui/src/app/dashboard/states/entity-state-controller.js | 2 +- ui/src/app/dashboard/states/entity-state-controller.scss | 2 +- ui/src/app/dashboard/states/entity-state-controller.tpl.html | 2 +- ui/src/app/dashboard/states/index.js | 2 +- .../app/dashboard/states/manage-dashboard-states.controller.js | 2 +- ui/src/app/dashboard/states/manage-dashboard-states.scss | 2 +- ui/src/app/dashboard/states/manage-dashboard-states.tpl.html | 2 +- ui/src/app/dashboard/states/select-target-state.controller.js | 2 +- ui/src/app/dashboard/states/select-target-state.tpl.html | 2 +- ui/src/app/dashboard/states/states-component.directive.js | 2 +- ui/src/app/dashboard/states/states-controller.service.js | 2 +- ui/src/app/device/add-device.tpl.html | 2 +- ui/src/app/device/add-devices-to-customer.controller.js | 2 +- ui/src/app/device/add-devices-to-customer.tpl.html | 2 +- ui/src/app/device/assign-to-customer.controller.js | 2 +- ui/src/app/device/assign-to-customer.tpl.html | 2 +- ui/src/app/device/device-card.tpl.html | 2 +- ui/src/app/device/device-credentials.controller.js | 2 +- ui/src/app/device/device-credentials.tpl.html | 2 +- ui/src/app/device/device-fieldset.tpl.html | 2 +- ui/src/app/device/device.controller.js | 2 +- ui/src/app/device/device.directive.js | 2 +- ui/src/app/device/device.routes.js | 2 +- ui/src/app/device/devices.tpl.html | 2 +- ui/src/app/device/index.js | 2 +- ui/src/app/entity-view/add-entity-view.tpl.html | 2 +- .../app/entity-view/add-entity-views-to-customer.controller.js | 2 +- ui/src/app/entity-view/add-entity-views-to-customer.tpl.html | 2 +- ui/src/app/entity-view/assign-to-customer.controller.js | 2 +- ui/src/app/entity-view/assign-to-customer.tpl.html | 2 +- ui/src/app/entity-view/entity-view-card.tpl.html | 2 +- ui/src/app/entity-view/entity-view-fieldset.tpl.html | 2 +- ui/src/app/entity-view/entity-view.controller.js | 2 +- ui/src/app/entity-view/entity-view.directive.js | 2 +- ui/src/app/entity-view/entity-view.routes.js | 2 +- ui/src/app/entity-view/entity-view.scss | 2 +- ui/src/app/entity-view/entity-views.tpl.html | 2 +- ui/src/app/entity-view/index.js | 2 +- ui/src/app/entity/alias/aliases-entity-select-button.tpl.html | 2 +- .../app/entity/alias/aliases-entity-select-panel.controller.js | 2 +- ui/src/app/entity/alias/aliases-entity-select-panel.tpl.html | 2 +- ui/src/app/entity/alias/aliases-entity-select.directive.js | 2 +- ui/src/app/entity/alias/aliases-entity-select.scss | 2 +- ui/src/app/entity/alias/entity-alias-dialog.controller.js | 2 +- ui/src/app/entity/alias/entity-alias-dialog.scss | 2 +- ui/src/app/entity/alias/entity-alias-dialog.tpl.html | 2 +- ui/src/app/entity/alias/entity-aliases.controller.js | 2 +- ui/src/app/entity/alias/entity-aliases.scss | 2 +- ui/src/app/entity/alias/entity-aliases.tpl.html | 2 +- ui/src/app/entity/attribute/add-attribute-dialog.controller.js | 2 +- ui/src/app/entity/attribute/add-attribute-dialog.tpl.html | 2 +- .../attribute/add-widget-to-dashboard-dialog.controller.js | 2 +- .../entity/attribute/add-widget-to-dashboard-dialog.tpl.html | 2 +- ui/src/app/entity/attribute/attribute-table.directive.js | 2 +- ui/src/app/entity/attribute/attribute-table.scss | 2 +- ui/src/app/entity/attribute/attribute-table.tpl.html | 2 +- ui/src/app/entity/attribute/edit-attribute-value.controller.js | 2 +- ui/src/app/entity/attribute/edit-attribute-value.tpl.html | 2 +- ui/src/app/entity/entity-autocomplete.directive.js | 2 +- ui/src/app/entity/entity-autocomplete.scss | 2 +- ui/src/app/entity/entity-autocomplete.tpl.html | 2 +- ui/src/app/entity/entity-filter-view.directive.js | 2 +- ui/src/app/entity/entity-filter-view.scss | 2 +- ui/src/app/entity/entity-filter-view.tpl.html | 2 +- ui/src/app/entity/entity-filter.directive.js | 2 +- ui/src/app/entity/entity-filter.scss | 2 +- ui/src/app/entity/entity-filter.tpl.html | 2 +- ui/src/app/entity/entity-list.directive.js | 2 +- ui/src/app/entity/entity-list.scss | 3 +-- ui/src/app/entity/entity-list.tpl.html | 2 +- ui/src/app/entity/entity-select.directive.js | 2 +- ui/src/app/entity/entity-select.scss | 3 +-- ui/src/app/entity/entity-select.tpl.html | 2 +- ui/src/app/entity/entity-subtype-autocomplete.directive.js | 2 +- ui/src/app/entity/entity-subtype-autocomplete.scss | 2 +- ui/src/app/entity/entity-subtype-autocomplete.tpl.html | 2 +- ui/src/app/entity/entity-subtype-list.directive.js | 2 +- ui/src/app/entity/entity-subtype-list.scss | 3 +-- ui/src/app/entity/entity-subtype-list.tpl.html | 2 +- ui/src/app/entity/entity-subtype-select.directive.js | 2 +- ui/src/app/entity/entity-subtype-select.scss | 2 +- ui/src/app/entity/entity-subtype-select.tpl.html | 2 +- ui/src/app/entity/entity-type-list.directive.js | 2 +- ui/src/app/entity/entity-type-list.scss | 3 +-- ui/src/app/entity/entity-type-list.tpl.html | 2 +- ui/src/app/entity/entity-type-select.directive.js | 2 +- ui/src/app/entity/entity-type-select.scss | 3 +-- ui/src/app/entity/entity-type-select.tpl.html | 2 +- ui/src/app/entity/index.js | 2 +- ui/src/app/entity/relation/relation-dialog.controller.js | 2 +- ui/src/app/entity/relation/relation-dialog.scss | 2 +- ui/src/app/entity/relation/relation-dialog.tpl.html | 2 +- ui/src/app/entity/relation/relation-filters.directive.js | 2 +- ui/src/app/entity/relation/relation-filters.scss | 2 +- ui/src/app/entity/relation/relation-filters.tpl.html | 2 +- ui/src/app/entity/relation/relation-table.directive.js | 2 +- ui/src/app/entity/relation/relation-table.scss | 2 +- ui/src/app/entity/relation/relation-table.tpl.html | 2 +- .../entity/relation/relation-type-autocomplete.directive.js | 2 +- ui/src/app/entity/relation/relation-type-autocomplete.scss | 2 +- ui/src/app/entity/relation/relation-type-autocomplete.tpl.html | 2 +- ui/src/app/event/event-content-dialog.controller.js | 2 +- ui/src/app/event/event-content-dialog.tpl.html | 2 +- ui/src/app/event/event-header-debug-rulenode.tpl.html | 2 +- ui/src/app/event/event-header-error.tpl.html | 2 +- ui/src/app/event/event-header-lc-event.tpl.html | 2 +- ui/src/app/event/event-header-stats.tpl.html | 2 +- ui/src/app/event/event-header.directive.js | 2 +- ui/src/app/event/event-row-debug-rulenode.tpl.html | 2 +- ui/src/app/event/event-row-error.tpl.html | 2 +- ui/src/app/event/event-row-lc-event.tpl.html | 2 +- ui/src/app/event/event-row-stats.tpl.html | 2 +- ui/src/app/event/event-row.directive.js | 2 +- ui/src/app/event/event-table.directive.js | 2 +- ui/src/app/event/event-table.tpl.html | 2 +- ui/src/app/event/event.scss | 2 +- ui/src/app/event/index.js | 2 +- ui/src/app/extension/extension-dialog.controller.js | 2 +- ui/src/app/extension/extension-dialog.tpl.html | 2 +- ui/src/app/extension/extension-table.directive.js | 2 +- ui/src/app/extension/extension-table.scss | 2 +- ui/src/app/extension/extension-table.tpl.html | 2 +- .../extensions-forms/extension-form-http.directive.js | 2 +- .../extension/extensions-forms/extension-form-http.tpl.html | 2 +- .../extensions-forms/extension-form-modbus.directive.js | 2 +- .../extension/extensions-forms/extension-form-modbus.tpl.html | 2 +- .../extensions-forms/extension-form-mqtt.directive.js | 2 +- .../extension/extensions-forms/extension-form-mqtt.tpl.html | 2 +- .../extension/extensions-forms/extension-form-opc.directive.js | 2 +- .../app/extension/extensions-forms/extension-form-opc.tpl.html | 2 +- ui/src/app/extension/extensions-forms/extension-form.scss | 2 +- ui/src/app/extension/index.js | 2 +- ui/src/app/global-interceptor.service.js | 2 +- ui/src/app/help/help-links.constant.js | 2 +- ui/src/app/help/help.directive.js | 2 +- ui/src/app/help/help.scss | 2 +- ui/src/app/home/home-links.controller.js | 2 +- ui/src/app/home/home-links.routes.js | 2 +- ui/src/app/home/home-links.scss | 2 +- ui/src/app/home/home-links.tpl.html | 2 +- ui/src/app/home/index.js | 2 +- ui/src/app/ie.support.js | 2 +- ui/src/app/import-export/import-dialog-csv.controller.js | 2 +- ui/src/app/import-export/import-dialog-csv.tpl.html | 2 +- ui/src/app/import-export/import-dialog.controller.js | 2 +- ui/src/app/import-export/import-dialog.scss | 2 +- ui/src/app/import-export/import-dialog.tpl.html | 2 +- ui/src/app/import-export/import-export.service.js | 2 +- ui/src/app/import-export/index.js | 2 +- ui/src/app/import-export/table-columns-assignment.directive.js | 3 +-- ui/src/app/import-export/table-columns-assignment.tpl.html | 2 +- ui/src/app/jsonform/index.js | 2 +- ui/src/app/jsonform/jsonform.controller.js | 2 +- ui/src/app/jsonform/jsonform.routes.js | 2 +- ui/src/app/jsonform/jsonform.scss | 2 +- ui/src/app/jsonform/jsonform.tpl.html | 2 +- ui/src/app/layout/breadcrumb-icon.filter.js | 2 +- ui/src/app/layout/breadcrumb-label.filter.js | 2 +- ui/src/app/layout/breadcrumb.tpl.html | 2 +- ui/src/app/layout/home.controller.js | 2 +- ui/src/app/layout/home.routes.js | 2 +- ui/src/app/layout/home.scss | 2 +- ui/src/app/layout/home.tpl.html | 2 +- ui/src/app/layout/index.js | 2 +- ui/src/app/layout/user-menu.directive.js | 2 +- ui/src/app/layout/user-menu.scss | 2 +- ui/src/app/layout/user-menu.tpl.html | 2 +- ui/src/app/locale/translate-handler.js | 2 +- ui/src/app/login/create-password.controller.js | 2 +- ui/src/app/login/create-password.tpl.html | 2 +- ui/src/app/login/index.js | 2 +- ui/src/app/login/login.controller.js | 2 +- ui/src/app/login/login.routes.js | 2 +- ui/src/app/login/login.scss | 2 +- ui/src/app/login/login.tpl.html | 2 +- ui/src/app/login/reset-password-request.controller.js | 2 +- ui/src/app/login/reset-password-request.tpl.html | 2 +- ui/src/app/login/reset-password.controller.js | 2 +- ui/src/app/login/reset-password.tpl.html | 2 +- ui/src/app/profile/change-password.controller.js | 2 +- ui/src/app/profile/change-password.tpl.html | 2 +- ui/src/app/profile/index.js | 2 +- ui/src/app/profile/profile.controller.js | 2 +- ui/src/app/profile/profile.routes.js | 2 +- ui/src/app/profile/profile.tpl.html | 2 +- ui/src/app/rulechain/add-link.tpl.html | 2 +- ui/src/app/rulechain/add-rulechain.tpl.html | 2 +- ui/src/app/rulechain/add-rulenode.tpl.html | 2 +- ui/src/app/rulechain/index.js | 2 +- ui/src/app/rulechain/link-fieldset.tpl.html | 2 +- ui/src/app/rulechain/link.directive.js | 2 +- ui/src/app/rulechain/link.scss | 2 +- ui/src/app/rulechain/message-type-autocomplete.directive.js | 2 +- ui/src/app/rulechain/message-type-autocomplete.scss | 2 +- ui/src/app/rulechain/message-type-autocomplete.tpl.html | 2 +- ui/src/app/rulechain/rulechain-card.tpl.html | 2 +- ui/src/app/rulechain/rulechain-fieldset.tpl.html | 2 +- ui/src/app/rulechain/rulechain.controller.js | 2 +- ui/src/app/rulechain/rulechain.directive.js | 2 +- ui/src/app/rulechain/rulechain.routes.js | 2 +- ui/src/app/rulechain/rulechain.scss | 2 +- ui/src/app/rulechain/rulechain.tpl.html | 2 +- ui/src/app/rulechain/rulechains.controller.js | 2 +- ui/src/app/rulechain/rulechains.tpl.html | 2 +- ui/src/app/rulechain/rulenode-config.directive.js | 2 +- ui/src/app/rulechain/rulenode-config.tpl.html | 2 +- ui/src/app/rulechain/rulenode-defined-config.directive.js | 2 +- ui/src/app/rulechain/rulenode-fieldset.tpl.html | 2 +- ui/src/app/rulechain/rulenode.directive.js | 2 +- ui/src/app/rulechain/rulenode.scss | 2 +- ui/src/app/rulechain/rulenode.tpl.html | 2 +- ui/src/app/rulechain/script/node-script-test.controller.js | 2 +- ui/src/app/rulechain/script/node-script-test.scss | 2 +- ui/src/app/rulechain/script/node-script-test.service.js | 2 +- ui/src/app/rulechain/script/node-script-test.tpl.html | 2 +- ui/src/app/services/clipboard.service.js | 2 +- ui/src/app/services/error-toast.tpl.html | 2 +- ui/src/app/services/info-toast.tpl.html | 2 +- ui/src/app/services/item-buffer.service.js | 2 +- ui/src/app/services/menu.service.js | 2 +- ui/src/app/services/success-toast.tpl.html | 2 +- ui/src/app/services/toast.controller.js | 2 +- ui/src/app/services/toast.js | 2 +- ui/src/app/services/toast.scss | 2 +- ui/src/app/services/toast.service.js | 2 +- ui/src/app/tenant/add-tenant.tpl.html | 2 +- ui/src/app/tenant/index.js | 2 +- ui/src/app/tenant/tenant-card.tpl.html | 2 +- ui/src/app/tenant/tenant-fieldset.tpl.html | 2 +- ui/src/app/tenant/tenant.controller.js | 2 +- ui/src/app/tenant/tenant.directive.js | 2 +- ui/src/app/tenant/tenant.routes.js | 2 +- ui/src/app/tenant/tenants.tpl.html | 2 +- ui/src/app/url.handler.js | 2 +- ui/src/app/user/activation-link.controller.js | 2 +- ui/src/app/user/activation-link.dialog.tpl.html | 2 +- ui/src/app/user/add-user.controller.js | 2 +- ui/src/app/user/add-user.tpl.html | 2 +- ui/src/app/user/index.js | 2 +- ui/src/app/user/user-card.tpl.html | 2 +- ui/src/app/user/user-fieldset.scss | 2 +- ui/src/app/user/user-fieldset.tpl.html | 2 +- ui/src/app/user/user.controller.js | 2 +- ui/src/app/user/user.directive.js | 2 +- ui/src/app/user/user.routes.js | 2 +- ui/src/app/user/users.tpl.html | 2 +- ui/src/app/widget/add-widgets-bundle.tpl.html | 2 +- ui/src/app/widget/index.js | 2 +- ui/src/app/widget/lib/CanvasDigitalGauge.js | 2 +- ui/src/app/widget/lib/add-entity-panel.scss | 2 +- ui/src/app/widget/lib/add-entity-panel.tpl.html | 2 +- ui/src/app/widget/lib/alarm-status-filter-panel.scss | 2 +- ui/src/app/widget/lib/alarm-status-filter-panel.tpl.html | 2 +- ui/src/app/widget/lib/alarms-table-widget.js | 2 +- ui/src/app/widget/lib/alarms-table-widget.scss | 2 +- ui/src/app/widget/lib/alarms-table-widget.tpl.html | 2 +- ui/src/app/widget/lib/analogue-compass.js | 2 +- ui/src/app/widget/lib/analogue-linear-gauge.js | 2 +- ui/src/app/widget/lib/analogue-radial-gauge.js | 2 +- ui/src/app/widget/lib/canvas-digital-gauge.js | 2 +- .../widget/lib/date-range-navigator/date-range-navigator.js | 2 +- .../widget/lib/date-range-navigator/date-range-navigator.scss | 2 +- .../lib/date-range-navigator/date-range-navigator.tpl.html | 2 +- ui/src/app/widget/lib/display-columns-panel.scss | 2 +- ui/src/app/widget/lib/display-columns-panel.tpl.html | 2 +- ui/src/app/widget/lib/entities-hierarchy-widget.js | 3 +-- ui/src/app/widget/lib/entities-hierarchy-widget.scss | 3 +-- ui/src/app/widget/lib/entities-hierarchy-widget.tpl.html | 2 +- ui/src/app/widget/lib/entities-table-widget.js | 2 +- ui/src/app/widget/lib/entities-table-widget.scss | 2 +- ui/src/app/widget/lib/entities-table-widget.tpl.html | 2 +- ui/src/app/widget/lib/extensions-table-widget.js | 2 +- ui/src/app/widget/lib/extensions-table-widget.scss | 2 +- ui/src/app/widget/lib/extensions-table-widget.tpl.html | 2 +- ui/src/app/widget/lib/flot-widget.js | 2 +- ui/src/app/widget/lib/google-map.js | 2 +- ui/src/app/widget/lib/image-map.js | 2 +- ui/src/app/widget/lib/map-widget.js | 2 +- ui/src/app/widget/lib/map-widget2.js | 2 +- ui/src/app/widget/lib/multiple-input-widget.js | 2 +- ui/src/app/widget/lib/multiple-input-widget.scss | 2 +- ui/src/app/widget/lib/multiple-input-widget.tpl.html | 2 +- ui/src/app/widget/lib/openstreet-map.js | 2 +- ui/src/app/widget/lib/rpc/index.js | 2 +- ui/src/app/widget/lib/rpc/knob.directive.js | 2 +- ui/src/app/widget/lib/rpc/knob.scss | 2 +- ui/src/app/widget/lib/rpc/knob.tpl.html | 2 +- ui/src/app/widget/lib/rpc/led-indicator.directive.js | 2 +- ui/src/app/widget/lib/rpc/led-indicator.scss | 2 +- ui/src/app/widget/lib/rpc/led-indicator.tpl.html | 2 +- ui/src/app/widget/lib/rpc/round-switch.directive.js | 2 +- ui/src/app/widget/lib/rpc/round-switch.scss | 2 +- ui/src/app/widget/lib/rpc/round-switch.tpl.html | 2 +- ui/src/app/widget/lib/rpc/switch.directive.js | 2 +- ui/src/app/widget/lib/rpc/switch.scss | 2 +- ui/src/app/widget/lib/rpc/switch.tpl.html | 2 +- ui/src/app/widget/lib/tencent-map.js | 2 +- ui/src/app/widget/lib/timeseries-table-widget.js | 2 +- ui/src/app/widget/lib/timeseries-table-widget.scss | 2 +- ui/src/app/widget/lib/timeseries-table-widget.tpl.html | 2 +- ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js | 2 +- ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss | 3 +-- .../widget/lib/tripAnimation/trip-animation-widget.tpl.html | 2 +- ui/src/app/widget/lib/web-camera-input-widget.js | 2 +- ui/src/app/widget/lib/web-camera-input-widget.scss | 3 +-- ui/src/app/widget/lib/web-camera-input-widget.tpl.html | 2 +- ui/src/app/widget/lib/widget-utils.js | 2 +- ui/src/app/widget/save-widget-type-as.controller.js | 2 +- ui/src/app/widget/save-widget-type-as.tpl.html | 2 +- ui/src/app/widget/select-widget-type.controller.js | 2 +- ui/src/app/widget/select-widget-type.tpl.html | 2 +- ui/src/app/widget/widget-editor.controller.js | 2 +- ui/src/app/widget/widget-editor.scss | 2 +- ui/src/app/widget/widget-editor.tpl.html | 2 +- ui/src/app/widget/widget-library.controller.js | 2 +- ui/src/app/widget/widget-library.routes.js | 2 +- ui/src/app/widget/widget-library.tpl.html | 2 +- ui/src/app/widget/widgets-bundle-card.tpl.html | 2 +- ui/src/app/widget/widgets-bundle-fieldset.tpl.html | 2 +- ui/src/app/widget/widgets-bundle.controller.js | 2 +- ui/src/app/widget/widgets-bundle.directive.js | 2 +- ui/src/app/widget/widgets-bundles.tpl.html | 2 +- ui/src/index.html | 2 +- ui/src/scss/animations.scss | 2 +- ui/src/scss/constants.scss | 2 +- ui/src/scss/fonts.scss | 2 +- ui/src/scss/main.scss | 2 +- ui/src/scss/mixins.scss | 2 +- ui/webpack.config.dev.js | 2 +- ui/webpack.config.js | 2 +- ui/webpack.config.prod.js | 2 +- 1915 files changed, 1915 insertions(+), 1934 deletions(-) diff --git a/application/build.gradle b/application/build.gradle index 1d6017c964..1ea603039a 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2019 The Thingsboard Authors + * Copyright © 2016-2020 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. diff --git a/application/pom.xml b/application/pom.xml index 06e2437417..881c35f87d 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -1,6 +1,6 @@